Jump to: navigation, search

Difference between revisions of "TaskFlow/Engines"

(Initial description of the idea.)
 
(Added 'why' section)
Line 23: Line 23:
  
 
It would be nice and cool and actually useful to split the flow into
 
It would be nice and cool and actually useful to split the flow into
three entities so that this responsibilities become separated. Here they
+
three entities so that this responsibilities become separated.
are.
+
 
 +
== Why (Three Highly Disputable Statements) ==
 +
 
 +
If pattern secifies implementation details, it is not a "pattern", but something else.
 +
 
 +
If logbook does not know about the latest state changes, it is doomed to fail to solve the problems it was made for.
 +
 
 +
Something should be done about it, like clarifying some of the basic abstractions, listed below.
  
 
== Pattern ==
 
== Pattern ==

Revision as of 14:46, 7 August 2013


Disclamer

This is very initial description of the idea of one developer (imelnikov), who even is not (yet) taskflow contributor. Don't consider it to be actual design doc for taskflow or something like that.

The idea

As of this writing, flow classes (under taskflow.patterns pacakge) have several responsibilities.

Describing flow structure: implicit and explicit dependencies between tasks and task ordering are part of flow definition.

Hold runtime data: task results and states are part of flow instances internal states (see e.g. taskflow.patterns.linear_flow.Flow.results).

Executing the task: flow is responsible to select next task(s) to run or revert based on flow structure and current state and actually run the code.

It would be nice and cool and actually useful to split the flow into three entities so that this responsibilities become separated.

Why (Three Highly Disputable Statements)

If pattern secifies implementation details, it is not a "pattern", but something else.

If logbook does not know about the latest state changes, it is doomed to fail to solve the problems it was made for.

Something should be done about it, like clarifying some of the basic abstractions, listed below.

Pattern

Pattern is a tool to describe structure.

Possible pattern examples are:

  • Linear -- run one task after another;
  • Parallel -- just run all the tasks, in any order or even simultaneously;
  • DAG -- run tasks with dependency-driven ordering, with no cycles;
  • Generic graph -- run tasks with dependency-driven ordering, potentially with cycles;
  • Blocks -- combine all of above into more complicated structure.

The idea is that graph flow (based on topological sort) and threaded flow (work in progress as of this writing, https://review.openstack.org/34488) are the same flow patterns: graph is build from task dependencies, which is analysed to get task ordering. You can run the same tasks via distributed flow on celery, and it will be same flow.

Because what's matter is code that runs, and everything else are details (though important ones, where devils do hide).

It would be cool to be able to specify how flow is run at runtime or in a configuration file: simple stuff for debugging tasks, distributed for lagre-scale deployments, etc. This is how we come to...

Engine

Engine is what really runs the tasks. It should take flow structure (described by patterns) and use it to decide which task to run and when.

Possible engines include:

  • simple one -- just takes e.g. linear flow and runs tasks from it one after another, never bothering itself with dependency graphs and such stuff -- should be useful for debugging tasks;
  • topological -- builds dependency graph from patterns and sorts tasks topologically by it;
  • threaded -- same as topological, but runs tasks in separate threads enabling them to run in parallel (even several implemetantions are possible);
  • distributed -- loads tasks to celery (or some other external service) that uses tasks deps to determine ordering.

Engines might have different capabilities. For example, topological engine will not interpret generic graph patterns because dependency cycles are error for it, while distributed engine should be fine with it.

Engines should implement same interface to make it easy to replace one engine with another. To describe this interface semantics some abstraction like TaskMachine would be useful -- every engine should behave 'as if' it is some kind of task machine.

Storage

We already have it in taskflow -- that's logbook. But it should be emphasized that logbook should become the authoritative, and, preferably, the only source of runtime state information. When task returns result, it should be written directly to logbook. When task or flow state changes in any way, logbook is first to know. Flow should not store task results -- there is logbook for that.

Logbook is responsible to store the actual data -- it specifies persistence mechanism (how data is saved and where -- memory, database, whatever), and persistence policy (when data is saved -- every time it changes or at some particular moments or simply never).