Dataflow async
Library ID dataflow-async
Latest version 1.0.5

FlowStrategy

Each attribute we create (either directly or with a transformation functions) has its own flow strategy that defines how the inner AttributeData is calculated and is expressed through the FlowStrategy sealed class.

Currently there are three possible choices:

  • Consistent: the task will be executed in a background thread and while doing so the internal status will be set to loading.
  • Eventually consistent: the task will be executed in a background thread but the old value will be kept until the new one is produced. The status will be set to loading only when the first time the value is being calculated or the previous state was error.
  • Synchronous: the task will be executed in the thread the triggered the calculation. The old value will be kept until the new one is set. The status will never be set to loading. The behavior is similar to a standard lazy field, with the difference that the status could be error.

If not explicitly specified, the default flow strategy for the attributeOf() function is FlowStrategy.CONSISTENT, while for transformations it's FlowStrategy.EVENUTALLY_CONSISTENT, in order to avoid spamming loading statues though the transformation chain every time something changes.

When a task needs to be executed in a background thread a ThreadPoolExecutor is internally used.

val attr = attributeOf(lazy=false, flowStrategy=FlowStrategy.CONSISTENT) { expensiveComputation("1 + 1") } //Since not lazy it immediately starts the computation on a background thread, status is LOADING //๐Ÿ•’ Some time passes... //Computation ends, status becomes LOADED attr.recompute() //Trigger recomputation //Status goes immediately to LOADING //๐Ÿ•’ Some time passes... //Computation ends, status becomes LOADED
Attribute<Integer> = Attribute.of(false, FlowStrategy.CONSISTENT, workContext -> { return expensiveComputation("1 + 1"); }); //Since not lazy it immediately starts the computation on a background thread, status is LOADING //๐Ÿ•’ Some time passes... //Computation ends, status becomes LOADED attr.recompute(); //Trigger recomputation //Status goes immediately to LOADING //๐Ÿ•’ Some time passes... //Computation ends, status becomes LOADED
val attr = attributeOf(lazy=false, flowStrategy=FlowStrategy.EVENTUALLY_CONSISTENT) { expensiveComputation("1 + 1") } //Since not lazy it immediately starts the computation on a background thread, status is LOADING //๐Ÿ•’ Some time passes... //Computation ends, status becomes LOADED attr.recompute() //Trigger recomputation //Status remains to LOADED with the old value //๐Ÿ•’ Some time passes... //Computation ends, status becomes LOADED with the new value
Attribute<Integer> = Attribute.of(false, FlowStrategy.EVENTUALLY_CONSISTENT, workContext -> { return expensiveComputation("1 + 1"); }); //Since not lazy it immediately starts the computation on a background thread, status is LOADING //๐Ÿ•’ Some time passes... //Computation ends, status becomes LOADED attr.recompute(); //Trigger recomputation //Status remains to LOADED with the old value //๐Ÿ•’ Some time passes... //Computation ends, status becomes LOADED with the new value
//Since not lazy it immediately starts the computation on the current thread val attr = attributeOf(lazy=false, flowStrategy=FlowStrategy.SYNCHRONOUS) { expensiveComputation("1 + 1") } //When attr is available status will be LOADED with the calculated value attr.recompute() //Trigger recomputation on the current thread //When recompute() returns the status will be LOADED with the newly calculated value
//Since not lazy it immediately starts the computation on the current thread Attribute<Integer> = Attribute.of(false, FlowStrategy.SYNCHRONOUS, workContext -> { return expensiveComputation("1 + 1"); }); //When attr is available status will be LOADED with the calculated value attr.recompute(); //Trigger recomputation on the current thread //When recompute() returns the status will be LOADED with the newly calculated value