@@ -4,13 +4,13 @@ A More In-Depth Look at Some of SpiffWorkflow's Features
44BPMN Task Specs
55---------------
66
7- BPMN Tasks inherit quite a few attributes from `SpiffWorkflow.specs.base.TaskSpec `, but only a few are used.
7+ BPMN Tasks inherit quite a few attributes from :code: `SpiffWorkflow.specs.base.TaskSpec `, but only a few are used.
88
9- * `name `: the unique id of the task spec , and it will correspond to the BPMN ID if that is present
9+ * `name `: the unique id of the TaskSpec , and it will correspond to the BPMN ID if that is present
1010* `description `: we use this attribute to provide a description of the BPMN type (the text that appears here can be overridden in the parser)
11- * `inputs `: a list of task spec `names ` that are parents of this task spec
12- * `outputs `: a list of task spec `names ` that are children of this task spec
13- * `manual `: :code: `True ` if human input is required to complete tasks associated with this spec
11+ * `inputs `: a list of TaskSpec `names ` that are parents of this TaskSpec
12+ * `outputs `: a list of TaskSpec `names ` that are children of this TaskSpec
13+ * `manual `: :code: `True ` if human input is required to complete tasks associated with this TaskSpec
1414
1515BPMN Tasks have the following additional attributes.
1616
@@ -20,12 +20,12 @@ BPMN Tasks have the following additional attributes.
2020* `documentation `: the contents of the BPMN `documentation ` element for the Task
2121* `data_input_associations `: a list of incoming data object references
2222* `data_output_associtions `: a list of outgoing data object references
23- * `io_specification `: the BPMN IO Specification of the Task
23+ * `io_specification `: the BPMN IO specification of the Task
2424
2525Filtering Tasks
2626---------------
2727
28- Tasks by lane
28+ Tasks by Lane
2929^^^^^^^^^^^^^
3030
3131The :code: `workflow.get_ready_user_tasks ` method optionally takes the argument `lane `, which can be used to
@@ -44,13 +44,14 @@ To retrieve a list of tasks associated with a particular task spec, use :code:`w
4444
4545.. code :: python
4646
47- tasks = workflow.get_tasks_from_spec_name(' customize_prodcut ' )
47+ tasks = workflow.get_tasks_from_spec_name(' customize_product ' )
4848
4949 will return a list containing the Call Actitivities for the customization of a product in our example workflow.
5050
5151.. note ::
5252
53- The `name ` paramter here refers to the task spec name, not the BPMN name
53+ The `name ` paramter here refers to the task spec name, not the BPMN name (for visible tasks, this will
54+ be the same as the `bpmn_id `)
5455
5556Tasks by State
5657^^^^^^^^^^^^^^
@@ -70,7 +71,7 @@ Tasks in a Subprocess or Call Activity
7071^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
7172
7273The :code: `BpmnWorkflow ` class maintains a dictionary of subprocesses (the key is the `id ` of the Call Activity or
73- Subprocess task ). :code: `workflow.get_tasks ` will start at the top level workflow and recurse through the subprocesses
74+ Subprocess Task ). :code: `workflow.get_tasks ` will start at the top level workflow and recurse through the subprocesses
7475to create a list of all tasks. It is also possible to start from a particular subprocess:
7576
7677.. code :: python
@@ -83,7 +84,7 @@ will limit the list of returned tasks to only those in the first product customi
8384
8485.. note ::
8586
86- Each :code: `Task ` object has a reference to its workflow; so with a task inside a subprocess, we can call
87+ Each :code: `Task ` object has a reference to its workflow; so with a Task inside a subprocess, we can call
8788 :code: `workflow.get_tasks(workflow=task.workflow) ` to start from our current workflow.
8889
8990Logging
@@ -104,19 +105,22 @@ we define a custom log level
104105
105106.. code :: python
106107
107- logging.addLevelName(15 , ' DATA_LOG ' )
108+ logging.addLevelName(15 , ' DATA ' )
108109
109110 so that we can see the task data in the logs without fully enabling debugging.
110111
111112The workflow runners take an `-l ` argument that can be used to specify the logging level used when running the example workflows.
112113
113114We'll write the logs to a file called `data.log ` instead of the console to avoid printing very long messages during the workflow.
114115
116+ Our logging configuration code can be found in `runner/shared.py `. Most of the code is about logging
117+ configuration in Python rather than anything specific to SpiffWorkflow, so we won't go over it in depth.
118+
115119Parsing
116120-------
117121
118122Each of the BPMN pacakges (:code: `bpmn `, :code: `spiff `, or :code: `camunda `) has a parser that is preconfigured with
119- the specs in that package (if a particular task spec is not implemented in the package, :code: `bpmn ` task is used).
123+ the specs in that package (if a particular TaskSpec is not implemented in the package, :code: `bpmn ` TaskSpec is used).
120124
121125See the example in :doc: `synthesis ` for the basics of creating a parser. The parser can optionally be initialized with
122126
@@ -126,27 +130,27 @@ See the example in :doc:`synthesis` for the basics of creating a parser. The pa
126130 :code: `SpiffWorkflow.bpmn.parser.spec_descriptions `. These values will be added to the Task Spec in the `description ` attribute
127131 and are intended as a user-friendly description of what the task is.
128132
129- The :code: `BpmnValidator ` can be used independently of the parser as well; call :code: `validate ` with an :code: ` lxml `
130- parsed tree.
133+ The :code: `BpmnValidator ` can be used and extended independently of the parser as well; call :code: `validate ` with
134+ an :code: ` lxml ` parsed tree.
131135
132136Loading BPMN Files
133137^^^^^^^^^^^^^^^^^^
134138
135- In addition to `load_bpmn_file `, there are similar functions `load_bpmn_str ` which can load the XML from a string, and
136- `load_bpmn_io `, which can load XML from any object implementing the IO interface, and `add_bpmn_xml `, which can load
139+ In addition to :code: `load_bpmn_file `, there are similar functions :code: `load_bpmn_str ` which can load the XML from a string, and
140+ :code: `load_bpmn_io `, which can load XML from any object implementing the IO interface, and :code: `add_bpmn_xml `, which can load
137141BPMN specs from an :code: `lxml ` parsed tree.
138142
139143Dependencies
140144^^^^^^^^^^^^
141145
142146The following methods are available for discovering the names of processes and DMN files that may be defined externally:
143147
144- - `get_subprocess_specs `: Returns a mapping of name -> :code: `BpmnWorkflowSpec ` for any Call Activities referenced by the
148+ - :code: `get_subprocess_specs `: Returns a mapping of name -> :code: `BpmnWorkflowSpec ` for any Call Activities referenced by the
145149 provided spec (searches recursively)
146- - `find_all_spec `: Returns a mapping of name -> :code: `BpmnWorkflowSpec ` for all processes used in all files that have been
150+ - :code: `find_all_spec `: Returns a mapping of name -> :code: `BpmnWorkflowSpec ` for all processes used in all files that have been
147151 provided to the parser at that point.
148- - `get_process_dependences `: Returns a list of process IDs referenced by the provided process ID
149- - `get_dmn_dependencies `: Returns a list of DMN IDs referenced byt he provided process ID
152+ - :code: `get_process_dependences `: Returns a list of process IDs referenced by the provided process ID
153+ - :code: `get_dmn_dependencies `: Returns a list of DMN IDs referenced byt he provided process ID
150154
151155
152156Serialization
@@ -157,7 +161,7 @@ The :code:`BpmnWorkflowSerializer` has two components
157161* the `workflow_spec_converter ` (which handles serialization of objects that SpiffWorkflow knows about)
158162* the `data_converter ` (which handles serialization of custom objects)
159163
160- Unless you have overriden any of the task specs with custom specs, you should be able to use the serializer
164+ Unless you have overriden any of TaskSpecs with custom specs, you should be able to use the serializer
161165configuration from the package you are importing the parser from (:code: `bpmn `, :code: `spiff `, or :code: `camunda `).
162166See :doc: `synthesis ` for an example.
163167
@@ -167,12 +171,12 @@ Serializing Custom Objects
167171In `Custom Script Engines `_ , we add some custom methods and objects to our scripting environment. We create a simple
168172class (a :code: `namedtuple `) that holds the product information for each product.
169173
170- In this particular case, Python will serialize instances of :code: `ProductInfo `, but they'll be converted to lists. And
171- of course, in most cases where you would use a custom class, it is probably *not * going to be JSON-serializable. So we'll
172- use this example to show how you might handle such a case.
174+ We'd like to be ble to save and restore our custom object.
173175
174176.. code :: python
175177
178+ ProductInfo = namedtuple(' ProductInfo' , [' color' , ' size' , ' style' , ' price' ])
179+
176180 def product_info_to_dict (obj ):
177181 return {
178182 ' color' : obj.color,
@@ -196,7 +200,7 @@ Registering an object sets up relationships between the class and the serializat
196200over how this works in a little more detail in `Custom Serialization in More Depth `_.
197201
198202It is also possible to bypass using a :code: `DictionaryConverter ` at all for the data serialization process (but not for
199- the spec serialization process). The only requirement the `data_converter ` requires is that it implement the methods
203+ the spec serialization process). The only requirement for the the `data_converter ` is that it implement the methods
200204
201205- `convert `, which takes an object and returns something JSON-serializable
202206- `restore `, which takes a serialized version and returns an object
@@ -220,7 +224,7 @@ to the next if they were serialized in an earlier format.
220224
221225If you've overridden the serializer version, you may need to incorporate our serialization changes with
222226your own. You can find our conversions in
223- `version_migrations.py <https://github.com/sartography/SpiffWorkflow/blob /main/SpiffWorkflow/bpmn/serializer/version_migration.py >`_
227+ `SpiffWorkflow/bpmn/serilaizer/migrations <https://github.com/sartography/SpiffWorkflow/tree /main/SpiffWorkflow/bpmn/serializer/migration >`_
224228
225229These are broken up into functions that handle each individual change, which will hopefully make it easier to incoporate them
226230into your upgrade process, and also provides some documentation on what has changed.
@@ -309,7 +313,7 @@ implement the calls in functions and add those functions to the scripting enviro
309313can be called by Script Tasks.
310314
311315We are not going to actually include a database or API and write code for connecting to and querying
312- it, but we can model our database with a simple dictionary lookup since we only have 7 products
316+ it, but since we only have 7 products we can model our database with a simple dictionary lookup
313317and just return the same static info for shipping for the purposes of the tutorial.
314318
315319We'll define some resources in `product_info.py `
@@ -390,6 +394,19 @@ script. We've imported our custom methods into `subprocess.py` so they are auto
390394This example is needlessly complex for the work we're doing in this case, but the point of the example is to demonstrate
391395that this could be a Docker container with a complex environment, an HTTP API running somewhere else entirely.
392396
397+ .. note ::
398+
399+ Note that our execute method returns :code: `True `. We could check the status of our process here and return
400+ :code: `False ` to force our task into an `ERROR ` state if the task failed to execute.
401+
402+ We could also return :code: `None `
403+ if the task is not finished; this will cause the task to go into the `STARTED ` state. You would have to manually
404+ complete a task that has been `STARTED `. The purpose of the state is to tell SpiffWorkflow your application will
405+ handle monitoring and updating this task and other branches that do not depend on this task may proceed. It is
406+ intended to be used with potentially long-running tasks.
407+
408+ See :doc: `../concepts ` for more information about Task States and Workflow execution.
409+
393410Service Tasks
394411-------------
395412
@@ -433,7 +450,7 @@ This is our script engine and scripting enviroment:
433450
434451 Instead of adding our custom functions to the enviroment, we'll override :code: `call_service ` and call them directly
435452according to the `operation_name ` that was given. The :code: `spiff ` Service Task also evaluates the parameters
436- against the task data for us, so we can use those values when we do . The Service Task will also store our result in
453+ against the task data for us, so we can pass those in directly . The Service Task will also store our result in
437454a user-specified variable.
438455
439456We need to send the result back as json, so we'll reuse the functions we wrote for the serializer.
@@ -459,15 +476,18 @@ The XML for the Service Task looks like this:
459476 <bpmn : outgoing >Flow_06k811b</bpmn : outgoing >
460477 </bpmn : serviceTask >
461478
462- Getting this information into the task is a little bit beyond the scope of this tutorial, as it involves more than
463- just SpiffWorkflow. I hand edited this XML; I do not recommend that (though it worked well enough for this case).
479+ Getting this information into the XML is a little bit beyond the scope of this tutorial, as it involves more than
480+ just SpiffWorkflow. I hand edited it for this case, but you can hardly ask your BPMN authors to do that!
464481
465- Our `bpmn.js <https://github.com/sartography/bpmn-js-spiffworkflow >`_ has a means of providing a list of services and
466- their parameters that can be displayed to a BPMN author. There is an example of hard-coding a list of services in
482+ Our `modeler <https://github.com/sartography/bpmn-js-spiffworkflow >`_ has a means of providing a list of services and
483+ their parameters that can be displayed to a BPMN author in the Service Task configurtion panel. There is an example of
484+ hard-coding a list of services in
467485`app.js <https://github.com/sartography/bpmn-js-spiffworkflow/blob/0a9db509a0e85aa7adecc8301d8fbca9db75ac7c/app/app.js#L47 >`_
468- and as suggested, you could replace this with a API call.
486+ and as suggested, it would be reasonably straightforward to replace this with a API call. SpiffArena has robust
487+ mechanisms for handling this that might serve as a model for you.
469488
470- How this all works is obviously heavily dependent on your application, so we won't go into further detail here.
489+ How this all works is obviously heavily dependent on your application, so we won't go into further detail here, except
490+ to give you a bare bones starting point for implementing something yourself that meets your own needs.
471491
472492To run this workflow (you'll have to manually change which script engine you import):
473493
0 commit comments