Los bucles infinitos son un problema con el que nos podemos encontrar al trabajar con Drools, sobre todo si estamos empezando a conocerlo y aún no tenemos claros algunos conceptos.

Hay que tener en cuenta que, si tenemos una regla que modifica un objeto, esta modificación puede reactivar la misma regla u otras que, tras su ejecución, vuelvan a activar la primera. Podemos encontrar bucles realmente complejos y complicados de solventar programáticamente.

Para evitar estas situaciones disponemos de varios mecanismos:


1. usar el atributo “no-loop”

Este atributo impide que una regla se active a sí misma. Esto suele suceder si la ejecución de una regla modifica el valor de alguno de los atributos del objeto que la regla evalúa.

Por ejemplo, si creamos una regla para calcular el importe de una Reserva, la ejecución de esta provoca la modificación del atributo importeInicial y, por tanto, la reactivación de esta misma regla, dando lugar a un bucle infinito. Con el uso del atributo no-loop evitamos este comportamiento:

rule "Calcula importe reserva"
salience -10
no-loop
 when
   $r : Reserva()
 then
   double importe = com.antmendoza.helper.ReservaHelper.calculaImporte($r);
   modify($r){setImporteInicial(importe)};
end


2. anotar nuestras clases Java con “@PropertyReactive”

Otro caso con el que nos podemos encontrar es que la ejecución de una regla puede activar otra, la ejecución de la segunda volver a activar la primera, y así sucesivamente. En este caso el uso de no-loop no es suficiente dado que evita que una regla se active a sí misma pero no que sea activada por otras.

Anotando nuestras clases Java con @PropertyReactive (o nuestros FactType con @propertyReactive) le estamos diciendo a Drools que sólo reevalúe las reglas en las que existe una condición para el atributo modificado.

Siguiendo con el ejemplo, la ejecución de la regla “Calcula importe reserva” podría producir la activación de la siguiente:

rule "Importe de reserva mayor que 400, bonificación del 20%"
salience -20
 when
   $r: Reserva(importeInicial > new Double(400) )
 then
   double importe = $r.getImporteInicial() * 0.8;
   modify($r){setImporteFinal(importe)};
end

A su vez, la ejecución de esta podría volver a activar “Calcula importe reserva”. Para evitarlo basta con anotar nuestra clase Reserva con @PropertyReactive:

@PropertyReactive
public class Reserva implements Serializable {
 ...
}

Conviene remarcar que, al anotar nuestras clases con @PropertyReactive sólo se reevaluarán las reglas en las que exista una condición para el atributo modificado, importeInicial tras la ejecución de “Calcula importe reserva” e importeFinal tras la ejecución de “Importe de reserva mayor que 400, bonificación del 20%”.


3. establecer una configuración por defecto

Por último, es posible activar el comportamiento del apartado anterior para todos los objetos de nuestro sistema, utilizando la opción PropertySpecificOption.ALWAYS al configurar el KnowledgeBuilder de la siguiente forma:

KnowledgeBuilderConfiguration config = KnowledgeBuilderFactory.newKnowledgeBuilderConfiguration();
config.setOption(PropertySpecificOption.ALWAYS);
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder(config);


Como hemos visto, los mecanismos descritos evitan que la reevaluación y reactivación de reglas, una de las principales ventajas de Drools, produzca comportamientos indeseados.


Fuentes:

One thought on “¿Cómo evitar bucles infinitos en Drools?

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>