Unified API Developer Manual / Version 2406.1
Table Of ContentsSince processes and tasks are dynamic, interacting entities, their lifecycle needs to be explained in some detail.
Process States
The state chart of a process is shown in Figure 6.2, “States of a process”. After being created, a process is started, and may be suspended and resumed a number of times. Ultimately, the final task is completed and the process closes.
When a process is created, it does not immediately start running. Instead, the process remains
"not started" until its start
method is invoked. This way, the process' variables
can be initialized at leisure. Note that as long as the process is not started, its initial
view is active (see Section 6.5, “Workflow Variables and Views”). For example, this allows some
variables to be writable only during initialization, and allows different validation rules to
apply during setup and during the process' runtime.
When the start
method is invoked, the process becomes "running" and starts with
its first task. All relevant automated action and user interaction happens during the
execution of tasks. The process itself mostly serves to structure and coordinate their
execution.
While a process is running, it may be suspended at any time by invoking its
suspend
method. This stops all progress, be it in automated or user tasks. The
process can be continued by invoking the resume
method.
A process can terminate either normally, by reaching and completing its final task, or it may
be aborted by an invocation of its abort
method. Registered final actions are executed
and may perform some cleanup or archive process data, but cannot modify the process itself anymore.
After a short delay, the process and all its sub processes are destroyed, and all state and variable
values are irretrievably lost. If some part of the process' state is still of interest, a
process should handle this in a final action, or it should first be suspended and inspected before aborting it.
Automated Tasks
Now you will learn the lifecycle of tasks.
For simplicity, begin with an automated task. In the normal case, the task's state progresses linearly from left to right, shown in the state diagram in Figure 6.3, “States of an automated task”. The task is started by its process, or by the completion of its predecessor. It waits for its (optional) guard condition to become true. Then the automated actions are executed. When the automated actions are finished, the task becomes "completing". As soon as control is successfully transferred to the successor task, the task enters the "completed" state. The task structure of a process definition may contain loops, so a task that has been executed once may later be reached and start again. A task's lifecycle terminates when the containing process terminates.
Since the guard condition as well as the automated actions can contain customized code, error
conditions must be modeled explicitly. When the evaluation of a condition or the execution of
an action fails, or if a timer expires, the task is escalated, and will not automatically make
any further progress. The previous state before escalation is recorded (denoted as history
state (H*
) in the state diagram) and can be inquired using
Task#getEscalatedState().
If the failure was caused by external circumstances, it may make sense to retry the task after
resolving the problem. When the retry
method is invoked, the task goes back to
the state before escalation and tries to execute the condition or actions once more.
As described above, a process may be suspended. This operation cascades to all tasks contained in the process, which will all be suspended. Each task's state before suspension is recorded (denoted by the lower history state in Figure 6.3, “States of an automated task”), and can be inquired using Task#getSuspendedState(). The task can only continue when the complete process is resumed, which will move each task back to the state before it was suspended.
When a process is aborted, each of its tasks will be marked as aborted (making most methods unusable) and will be destroyed soon after.
User Tasks
While the execution of an automated task only consists of server-side actions, a user task's execution is split into several steps. As soon as the guard condition is true, a user task is activated, and waits for a user to accept the task. When a user accepts, on the server, the task's preconditions are checked, and the task's entry actions are executed. When the entry actions are finished, the task becomes running, and responsibility for further actions passes to the user. When the user has completed his or her part, the server checks the task's postconditions and runs the task's exit actions.
Figure 6.4, “States of a Task” is a combined state chart for automated and
user tasks. Look out for [isUserTask()]
conditions which annotate the differences between the
task types.
There are several transitions where customized server-side code is executed. In each of these cases, when something goes wrong, the task becomes escalated. Another potential cause for escalation is a timer expiring, for example because the user does not complete a task in the expected period. The mechanism for retry, suspend/resume and abort is the same as described for automated tasks above.
When a task is activated, that is its guard check has been passed, it may be offered to several users. By default, all users that have the right to accept the task (see Section 6.6, “The Access Control Service”), and have not rejected the task yet, appear in the set of offered users. A task may also be assigned directly to a user or to a group, or a certain performer may have been forced by a previous task. The strategy for offering tasks to users can be overridden by providing a customized performer policy (see the Workflow Manual for details), or by changing the handling of the accept right in a custom rights policy (see Section 6.10.8, “Rights Policies”).
The set of users a task is offered to may be inquired using the method Task#getOfferedTo(). All tasks that are offered to the current user can be determined using the work list service (see Section 6.4, “The Work List Service”). Changes to a task's set of offered users are signaled by TaskOfferedEvent and TaskRevokedEvent instances (see Section 6.8, “Events”). There are no events for changes to the work list. Instead, when working inside the CoreMedia CAE caching infrastructure, your code simply calls the work list getters, and can rely on the correct dependencies being registered behind the scenes. In this way, your code will be automatically reexecuted when any accessed work list changes. See the CoreMedia CAE Developer Manual and Section 4.10, “Caching” for further details.
A task's guard condition may become false before the task is accepted by any eligible user. In this case, the task goes back to the waiting state.
The user who accepts a task becomes the performer of the task. This entails certain privileges required to perform the task, namely the ability to read and write the task's variables, and the ability to cancel, complete or retry the task.
Before passing control to the user, first, the task's preconditions are checked. This feature can be used to verify assumptions by the workflow designer. If a condition is not met, the task is escalated. If all checks are passed, the task's entry actions are executed. This may include GUI-based remote client actions, which will be executed in the name of the user (see Section 6.10.9, “Remote Client Actions”).
The Unified API offers the method
Task#acceptAndEnter(),
which waits until the task has safely arrived in the running state. Any exceptions thrown by
failing preconditions or entry actions are passed on to the method's caller. This allows for a
synchronous programming model: When acceptAndEnter
returns normally, you can be
sure that the task is running. In contrast, accept
supports an asynchronous
programming model, insofar as it only triggers the server-side computation. When
accept
returns, the server-side code may not have finished yet.
A task can be passed directly from one performer to another using the method Task#delegate(). The task remains in the running state, no conditions are checked or actions executed.
A task may also be canceled, sending it back to the activated state. The user ceases to be the task's performer. Again, postconditions are not checked, and exit actions are not executed.
Note that these methods may also be invoked by a different user than the performer, assuming the respective rights are granted. For example, when a user is on vacation and has left behind some running task, an administrator or process owner may still lead the process to conclusion by delegating or canceling the task. An additional option for a user task is to skip the task, in order to make progress even when no suitable performer can be found.
A call to Task#complete() indicates to the workflow server that the user has finished his or her work. All configured postconditions are checked. If any post condition fails, the user probably has not fulfilled his task as planned. The task becomes escalated, and may be retried by the performer, returning it to the running state. Note that the current performer is remembered while the task is escalated and/or suspended.
After all postconditions are successfully checked, the configured exit actions are run, and
the task changes to state completing. Similar to acceptAndEnter
, the method
Task#completeAndExit()
synchronously waits until the task including all post conditions and server-side actions has
completed, and passes any exceptions on to its caller.
The remaining lifecycle is as described for automated tasks, above.