# Activity
An activity is a stable state where a [process instance](https://docs.workflowengine.io/get-started/concepts/process-instance/) waits. Activities are defined in
a [scheme](https://docs.workflowengine.io/get-started/concepts/scheme/). Every scheme has exactly one initial activity where new process instances start and can have zero
or more activities marked as final. A process instance leaves an activity when a [command](https://docs.workflowengine.io/get-started/concepts/command/) executes, a timer
fires, or an automatic [transition](https://docs.workflowengine.io/get-started/concepts/transition/) fires. A process instance is always positioned at exactly one activity
at a time.
During normal execution, when a process instance enters an activity, the activity can execute useful work
through [actions](https://docs.workflowengine.io/get-started/concepts/action/). Actions are blocks of code that run automatically upon entry, such as sending
notifications, updating business data, or calling external services. Actions are attached to the activity via the `Implementation` property.
## Activity properties
Each activity has a set of properties that define its identity, behavior, and position in the scheme.
### Core properties
These are the most commonly configured properties:
Table: Core activity properties
| Property | Type | Description |
|----------------|---------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------|
| Name | `string` | Case-sensitive, unique identifier for the activity within the scheme |
| State | `string` | The business state name associated with this activity; non-unique or absent |
| IsInitial | `bool` | Only one activity per scheme may be initial |
| IsFinal | `bool` | Marks a final activity; optional in regular schemes and required in schemes used for inlining |
| IsForSetState | `bool` | Marks this activity as the target when moving a process to a state by name. Only one activity per state value should have this enabled |
| Implementation | `list` of `ActionDefinitionReference` | Actions that execute when a process instance enters this activity |
### Scenario-specific properties
These properties are not always needed. Some are used in specialized scenarios such as disabling database persistence, setting timeouts, or
handling errors. Others are metadata helpers:
Table: Scenario-specific activity properties
| Property | Type | Description |
|---------------------------------|---------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------|
| IsAutoSchemeUpdate | `bool` | Allows the process instance to be updated to a new scheme version when it reaches this activity |
| UserComment | `string` | Optional custom comment attached to the activity |
| Annotations | `list` of `Annotation` | Key-value metadata attached to the activity; see Annotations |
| DisablePersistState | `bool` | Skips saving the current state of the process instance when entering this activity |
| DisablePersistTransitionHistory | `bool` | Skips saving the transition history entry when passing through this activity |
| DisablePersistParameters | `bool` | Skips saving the parameter values when entering this activity |
| ExecutionTimeout | `ActivityTimeout` | Limits activity execution time and cancels it when the interval expires; asynchronous actions must use the provided `CancellationToken` |
| IdleTimeout | `ActivityTimeout` | Limits how long the process instance may sit in this activity without any transition |
| ExceptionsHandlers | `list` of `ActivityExceptionsHandler` | Configures what should happen if an action throws an exception |
| PreExecutionImplementation | `list` of `ActionDefinitionReference` | Actions executed only during pre-execution simulation |
### Exception handling
When an action on an activity throws an exception, you can add exception handlers to the activity. If no handler processes the exception, it
reaches the normal workflow error handling.
Each handler has two parts: which exceptions to catch and what to do when one occurs. The runtime evaluates handlers by ascending `Order`
and uses the first matching handler. To catch a specific exception, use its full type name such as `System.InvalidOperationException`. To
catch any exception, use `*`, and place that handler after more specific handlers.
Four actions are available when an exception is caught:
- **SetActivity** - move the process instance to another activity. You specify which activity by name.
- **SetState** - move the process instance to a business state. The runtime finds the activity that matches that state.
- **Retry** - run the activity implementation again. You specify how many times to retry before giving up.
- **Ignore** - suppress the exception and continue workflow execution.
```xml
```
In this example, `InvalidOperationException` reaches the handler with `Order="1"`, so the process moves to the `Failed` activity. Any other
exception reaches the wildcard handler with `Order="2"` and retries the activity implementation up to three times.
### Execution and idle timeouts
An activity can have two timeouts that limit how long things can take.
- **ExecutionTimeout** - requests cancellation when activity execution exceeds the configured interval, then applies the configured result.
- **IdleTimeout** - limits how long the process instance can sit at this activity without any transition firing. If the timer expires, the
runtime takes the configured action.
`ExecutionTimeout` cancels execution through the `CancellationToken` passed to asynchronous actions and custom activity execution. It cannot
stop synchronous code or asynchronous code that ignores the token; the runtime waits for that code to finish before handling the timeout.
Each timeout defines an interval and what to do when it expires. `ExecutionTimeout` supports `SetActivity`, `SetState`, and `Retry`.
`IdleTimeout` supports `SetActivity` and `SetState`.
`IdleTimeout` is implemented as an interval timer and supports [work calendars](https://docs.workflowengine.io/get-started/concepts/work-calendar/) when its value uses
calendar-aware units such as `2wd` or `4 whours`. `ExecutionTimeout` parses a regular elapsed-time interval directly and does not use work
calendars.
```xml
```
In this example, if the process stays at the `Review` activity for more than 2 days without advancing, the runtime moves it to the
`Escalated` state.
### Disabling persistence
By default, the runtime saves the process state, its parameters, and the transition history to the database through
the [persistence](https://docs.workflowengine.io/get-started/concepts/persistence/) provider every time the process moves. For high-throughput scenarios where every
millisecond counts, you can skip some of these saves on a per-activity basis:
- **`DisablePersistState`** - skip saving the current state (activity and status) for this activity.
- **`DisablePersistParameters`** - skip saving the parameter values for this activity.
- **`DisablePersistTransitionHistory`** - skip saving the transition history entry when moving through this activity.
These flags do not affect reads - the runtime still loads state and parameters from the database when needed. They only disable the write
that happens after each transition. Use them on high-traffic activities where you are willing to lose the latest state data in exchange for
faster execution.
### Pre-execution implementation
An activity can have two sets of actions: the regular `Implementation` that runs during normal execution and `PreExecutionImplementation`
that runs only during pre-execution simulation. During simulation, the runtime uses
`PreExecutionImplementation` instead of `Implementation` for a visited activity.
Pre-execution actions should implement simulation-specific behavior. They can still call external systems, so adding an action to
`PreExecutionImplementation` does not make that action free of side effects.
```xml
```
### What is State
The `State` property represents the **business state**, which is the human-readable status such as "Draft", "Under Review", "Approved". An
`Activity` is the **physical state** that the runtime tracks internally. One `State` can be shared across multiple activities; for example,
"Under Review" can be the state for both a `ManagerReview` activity and a `DirectorReview` activity.
## Declaring activities in a scheme
Activities are listed in the `` section of a scheme. Each `` element defines one waiting point in the process.
Activities are connected by [transitions](https://docs.workflowengine.io/get-started/concepts/transition/), which determine the paths a process instance can take from one
activity to another.
The activity itself does not execute logic. It is a named waiting point that holds the process instance until an outgoing transition fires.
Actions run when the process instance arrives at an activity. Each activity can be configured to perform specific work, such as sending
notifications, changing data, or calling an external service. This work is defined by the
activity's [actions](https://docs.workflowengine.io/get-started/concepts/action/).
```xml
```
`IsInitial="true"` marks the activity where Workflow Engine positions new instances. `IsFinal="true"` is a marker: if execution stops in
that activity, the runtime sets the process status to `Finalized`. The marker does not prohibit outgoing transitions. A regular scheme may
have no final activities, but a scheme used for inlining must have at least one so the inlined fragment can connect back to its parent
scheme.
## Managing activities from code
You can move a process instance to a specific activity or state programmatically without going through a normal transition. These methods
are useful for error recovery, manual overrides, and testing.
### SetState method
`SetStateAsync` selects an activity whose `State` matches the requested name and whose `IsForSetState` property is `true`. By default, the
method executes that activity's `Implementation` and follows its automatic transitions, bypassing normal incoming transition conditions:
```csharp
var setStateParams = new SetStateParams(processId, "Approved");
await runtime.SetStateAsync(setStateParams);
```
### SetActivity method
Moves the process to a specific activity directly, without requiring its `State` or `IsForSetState` properties. You have two options:
- `SetActivityWithExecutionAsync` - moves and runs the activity's actions.
- `SetActivityWithoutExecutionAsync` - moves without running actions.
```csharp
var scheme = processInstance.ProcessScheme;
var activity = scheme.FindActivity("Review");
await runtime.SetActivityWithExecutionAsync(
"user-42", null, null, activity, processInstance);
```
### Resume process
`ResumeAsync` continues from the current activity, or from the activity named in `ResumeParams`, without executing that starting activity's
`Implementation` again. It evaluates the activity's outgoing automatic transitions and follows one when its conditions pass. Unlike
`SetStateAsync`, `ResumeAsync` does not select a target by business state or execute the selected starting activity:
```csharp
var result = await runtime.ResumeAsync(processId);
```
### Finding activities in a scheme
Every process instance holds a reference to its scheme. Use it to look up activities by name or find the starting point:
```csharp
var scheme = processInstance.ProcessScheme;
// Find the initial activity
var start = scheme.InitialActivity;
// Find a specific activity by name
var review = scheme.FindActivity("Review");
// List all activities
List allActivities = scheme.Activities;
```
`FindActivity` throws an exception if no activity with that name exists.
## See also
- [Transition](https://docs.workflowengine.io/get-started/concepts/transition/): Transitions connect activities and define what moves a process instance forward.
- [Command](https://docs.workflowengine.io/get-started/concepts/command/): Commands trigger transitions from an activity.
- [Scheme](https://docs.workflowengine.io/get-started/concepts/scheme/): A scheme organizes activities and transitions into a process definition.
- [Process Instance](https://docs.workflowengine.io/get-started/concepts/process-instance/): A process instance moves through activities and tracks its current position.
## Frequently asked questions
**What is an activity in Workflow Engine?**
An activity is a named stable state in a scheme where a process instance waits until a command, timer, or automatic transition moves it
forward. Every scheme has exactly one initial activity and may have zero or more activities marked as final.
**Can multiple activities share the same state?**
Yes. Multiple activities can have the same `State` value. For example, both a `ManagerReview` and a `DirectorReview` activity can use the
"Under Review" state. The activity name identifies the physical waiting point, while the state is the business status.
**Where are activities declared in a scheme?**
Activities are declared in the `` section of the scheme XML. Each `` element defines one waiting point, and activities
are connected by transitions that determine how a process instance moves from one to another.