= Execution of works
:description: == Definition

== Definition

A work is an execution unit. It is java runnable object executed in a thread pool. It's the most basic component of the Bonita Engine, and is central to the execution of processes.

A work often wraps one another to add specific behaviors.
An *ExecuteFlowNodeWork* contains the flownode execution logic.
It is wrapped in a *TxBonitaWork*, to ensure everything is executing inside a transaction.
It is itself wrapped into a *LockProcessInstanceWork*, to allow to lock any concurrent access to the same process instance. +
It is itself wrapped into a *InSessionBonitaWork*, to set the tenant context (tenantId).

== Basic call flow

The *ThreadPoolExecutor* is responsible for executing works. It calls the _work()_ method on the parent Work. The parent will then call  _work()_ on the wrapped work who will call _work()_ on its wrapped work and so on.

=== Example : flownode execution

The BonitaThreadPoolExecutor is responsible for executing the work. The basic call flow is explained below:

* The top-level work (of type *InSessionBonitaWork*) sets the tenantId and then calls the work() method on its wrapped lower-level work, which is of type *ProcessInstanceContextWork*.
* *ProcessInstanceContextWork* fills in some context information and then calls work() on its wrapped lower-level work, which is of type *LockProcessInstanceWork*.
* {blank}
+
[cols=2*]
|===
| *LockProcessInstanceWork* [[tries to obtain an exclusive lock
| Work-locking]] on the containing process instance corresponding to the flownode to execute:
|===

* If it cannot get the lock within 20ms (by default), a LockTimeoutException is thrown so that the work is placed at the end of the work queue, for later execution
* In any case, if the lock has been obtained, it is released after the execution (in a `finally` block)
* Then the wrapped *TxBonitaWork* is executed, which wraps the wrapped work into a JTA transaction
* Then the ExecuteFlowNodeWork executes its logic.

== Error management

There are 3 types of errors:

* No lock could be acquired.
* An exception of temporary nature occurred (Timeout, OptimisticLockException, database connection issues...).
* All the other type of exceptions.

If the lock could not be acquired a specific set of action occurs. [[see here|Work-locking]].
If an exception of temporary nature occurred, the work would be retried (see below).
Other exceptions are handled by the method _handleFailure()_ . On a flownode it sets its state to "failed".

=== Retry mechanism

When a work fails, there is a mechanism in place to retry it. If we identify that the issue that caused the work to fail is a temporary issue, we:

* put it at the end of the queue
* set a date before which the work should not be retried
* increment the `retryCount` of the `WorkDescriptor`

== Auditing

A special logger can help identify potential issue of work execution:

----
29-Jul-2020 17:24:04.674 AVERTISSEMENT [Bonita-Worker-1-09] org.bonitasoft.engine.work.audit.AuditListener.abnormalExecutionStatusDetected Potential abnormal execution detected - cause TOO_MANY_EXECUTIONS. org.bonitasoft.engine.work.WorkDescriptor@323b63d6[uuid=55a92f06-7061-43e9-8523-1c6955a26fc2,type=EXECUTE_FLOWNODE,tenantId=1,parameters={processDefinitionId=XXXX, processInstanceId=XXXX, stateCanceling=false, stateExecuting=false, stateId=37, stateAborting=false, flowNodeInstanceId=CCC},retryCount=Y,executionThreshold=2020-07-29T06:24:04.674Z,executionCount=10,registrationDate=2020-07-29T06:11:44.943Z,abnormalExecutionDetected=true]
----

In that case the warning tells us the work was taken for execution but not completed 10 times.

We can see here:

* `executionCount` is the counter of every time was taken for execution.
* `retryCount` is the counter of each time the work failed because of a retryable exception.

see xref:work-execution-audit.adoc[Work execution audit] for more details.
