# TraconWorkflowOptions

> Tracon documentation. Tracon is a .NET package family that adds a control
> plane on Microsoft Agent Framework, published as NuGet packages that run
> inside your own ASP.NET Core application.
>
> Page: https://tracon.dev/api/tracon.traconworkflowoptions/
> Summary: TraconWorkflowOptions: Settings that control workflow execution.

<div class="api-provenance">Namespace Tracon · Assembly <code>Tracon.Workflows.dll</code></div>

Settings that control workflow execution.

```csharp
public sealed class TraconWorkflowOptions
```

<dl class="api-relations"><dt>Inheritance</dt><dd><a href="https://learn.microsoft.com/dotnet/api/system.object">object</a> ← <a href="/api/tracon.traconworkflowoptions/">TraconWorkflowOptions</a></dd><dt>Inherited Members</dt><dd><a href="https://learn.microsoft.com/dotnet/api/system.object.gettype">object.GetType()</a>, <a href="https://learn.microsoft.com/dotnet/api/system.object.tostring">object.ToString()</a>, <a href="https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object)">object.Equals(object?)</a>, <a href="https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object)">object.Equals(object?, object?)</a>, <a href="https://learn.microsoft.com/dotnet/api/system.object.referenceequals">object.ReferenceEquals(object?, object?)</a>, <a href="https://learn.microsoft.com/dotnet/api/system.object.gethashcode">object.GetHashCode()</a></dd></dl>

## Constructors

### <a id="Tracon_TraconWorkflowOptions__ctor"></a> TraconWorkflowOptions\(\)

```csharp
public TraconWorkflowOptions()
```

## Fields

### <a id="Tracon_TraconWorkflowOptions_SectionName"></a> SectionName

The name of the configuration section.

```csharp
public const string SectionName = "Tracon:Workflows"
```

#### Field Value

 [string](https://learn.microsoft.com/dotnet/api/system.string)

## Properties

### <a id="Tracon_TraconWorkflowOptions_EnableCheckpointing"></a> EnableCheckpointing

Gets or sets whether checkpoint writing is enabled.

```csharp
public bool EnableCheckpointing { get; set; }
```

#### Property Value

 [bool](https://learn.microsoft.com/dotnet/api/system.boolean)

#### Remarks

The default is [true](https://learn.microsoft.com/dotnet/csharp/language-reference/builtin-types/bool): resuming works out of the box.
The cost is one write per super-step; [TraconWorkflowOptions.MaxSuperSteps](/api/tracon.traconworkflowoptions/#Tracon_TraconWorkflowOptions_MaxSuperSteps) and
the retention limit of the in-memory store keep this in check.

### <a id="Tracon_TraconWorkflowOptions_Enabled"></a> Enabled

Gets or sets whether workflow execution is enabled.

```csharp
public bool Enabled { get; set; }
```

#### Property Value

 [bool](https://learn.microsoft.com/dotnet/api/system.boolean)

#### Remarks

When disabled, the catalog is still listed; only execution is refused.
This lets execution be stopped during an incident without deleting the
definitions.

### <a id="Tracon_TraconWorkflowOptions_KeepCheckpointsAfterCompletion"></a> KeepCheckpointsAfterCompletion

Gets or sets whether the checkpoints of a completed run are kept.

```csharp
public bool KeepCheckpointsAfterCompletion { get; set; }
```

#### Property Value

 [bool](https://learn.microsoft.com/dotnet/api/system.boolean)

#### Remarks

The default is [true](https://learn.microsoft.com/dotnet/csharp/language-reference/builtin-types/bool): being resumable even after a
workflow has finished is the whole point of this feature. Setups that
want to avoid the storage cost can disable it; checkpoints then live
only while the run is in progress.

Checkpoints are kept per session. While another run of the same
session still needs them — one waiting for a human answer, or one still
running — a finished run leaves them in place, so a pending request
stays answerable after an earlier answer, even a rejected one. A run that
asked a human stays waiting even after an answer (a second answer opens a
new branch), so once a session has paused for input, this setting no
longer removes that session's checkpoints; retention does, for the runs
that are not waiting.

A run that a stopping worker cancels while [TraconWorkflowOptions.ResumeInterruptedRuns](/api/tracon.traconworkflowoptions/#Tracon_TraconWorkflowOptions_ResumeInterruptedRuns)
is on is not finished: its job continues it from the latest checkpoint. It
keeps its checkpoints, and the continuation, which shares the session,
removes them when it finishes.

### <a id="Tracon_TraconWorkflowOptions_MaxConcurrentRuns"></a> MaxConcurrentRuns

Gets or sets the maximum number of workflows that may run at the same time.

```csharp
public int MaxConcurrentRuns { get; set; }
```

#### Property Value

 [int](https://learn.microsoft.com/dotnet/api/system.int32)

#### Remarks

The limit is *shared across all tenants*, and it is per process. A
single workflow makes dozens of model calls; leaving it unbounded would
let one user consume an entire provider quota. To keep one tenant from
taking every slot, set [TraconWorkflowOptions.MaxConcurrentRunsPerTenant](/api/tracon.traconworkflowoptions/#Tracon_TraconWorkflowOptions_MaxConcurrentRunsPerTenant).

A run over the limit waits for a slot. Its record already exists while
it waits and shows `Queued` (it shows `Running` once it has a
slot); the wait counts toward [TraconWorkflowOptions.RunTimeout](/api/tracon.traconworkflowoptions/#Tracon_TraconWorkflowOptions_RunTimeout), and a run whose
deadline passes before it gets a slot closes like any other timed-out run.

### <a id="Tracon_TraconWorkflowOptions_MaxConcurrentRunsPerTenant"></a> MaxConcurrentRunsPerTenant

Gets or sets the most workflow runs one tenant may have going at the same time.
[null](https://learn.microsoft.com/dotnet/csharp/language-reference/keywords/null) (the default) sets no per-tenant limit.

```csharp
public int? MaxConcurrentRunsPerTenant { get; set; }
```

#### Property Value

 [int](https://learn.microsoft.com/dotnet/api/system.int32)?

#### Remarks

Without it, one tenant that starts many runs holds every slot of
[TraconWorkflowOptions.MaxConcurrentRuns](/api/tracon.traconworkflowoptions/#Tracon_TraconWorkflowOptions_MaxConcurrentRuns) and the queue's lease order, and the other tenants
wait. With it, the setting limits a tenant in two places:

- **In each process:** a tenant's runs beyond the limit wait for a tenant slot before they take one of the shared slots, so they never hold a shared slot while they wait. The run shows `Queued` until it has both slots. The limit is exact within one process.
- **In the job queue, across every process that shares the store:** a worker does not lease a queued workflow job (`Prefer: respond-async`, a scheduled or resumed workflow) of a tenant that already has this many workflow jobs leased, and leases the oldest job of another tenant instead. This count is read, not locked, so workers that lease at the same moment can take a tenant a little past the limit (by up to the number of workers); the in-process limit above stays exact.

The wait for a tenant slot counts toward [TraconWorkflowOptions.RunTimeout](/api/tracon.traconworkflowoptions/#Tracon_TraconWorkflowOptions_RunTimeout), like the wait for a
shared slot.

Must be from 1 to [TraconWorkflowOptions.MaxConcurrentRuns](/api/tracon.traconworkflowoptions/#Tracon_TraconWorkflowOptions_MaxConcurrentRuns); any other value fails at startup.

### <a id="Tracon_TraconWorkflowOptions_MaxNodeSettingsLength"></a> MaxNodeSettingsLength

Gets or sets the largest settings a single function node may carry, as bytes
of the settings' JSON text.

```csharp
public int MaxNodeSettingsLength { get; set; }
```

#### Property Value

 [int](https://learn.microsoft.com/dotnet/api/system.int32)

#### Remarks

A workflow definition is written whole on every save and read on every run,
and the workflow list returns every node. A node's settings are a handful of
values for the function's settings type; the cap keeps the definition from
becoming a data store. The default of 16 KiB is far above any settings object
a function declares by hand and far below a body worth keeping in a
definition.

The cap is checked when a definition is saved. A definition that was saved
before the cap was lowered still runs. Must be at least 1.

### <a id="Tracon_TraconWorkflowOptions_MaxRequestExpirationsPerScan"></a> MaxRequestExpirationsPerScan

Gets or sets the most requests one scan closes ([TraconWorkflowOptions.RequestExpirationScanInterval](/api/tracon.traconworkflowoptions/#Tracon_TraconWorkflowOptions_RequestExpirationScanInterval)).

```csharp
public int MaxRequestExpirationsPerScan { get; set; }
```

#### Property Value

 [int](https://learn.microsoft.com/dotnet/api/system.int32)

#### Remarks

The default is 100. A backlog is closed over several scans. Must be at least 1.

### <a id="Tracon_TraconWorkflowOptions_MaxResumeAttempts"></a> MaxResumeAttempts

Gets or sets how many continuation runs one interrupted run may get while
[TraconWorkflowOptions.ResumeInterruptedRuns](/api/tracon.traconworkflowoptions/#Tracon_TraconWorkflowOptions_ResumeInterruptedRuns) is on.

```csharp
public int MaxResumeAttempts { get; set; }
```

#### Property Value

 [int](https://learn.microsoft.com/dotnet/api/system.int32)

#### Remarks

The default is one. The count is per chain: a continuation that is itself
interrupted counts against the same limit. Past it, the job item (or the
queued run's job) is failed instead of continued, and the last run of the
chain is left `Failed`. Zero turns continuation off but keeps the
detection: an interrupted run is closed as `Failed` and its item fails,
instead of running the workflow again from the beginning.

The worker fails a job's lease past its attempt limit before the job's
handler runs, so the job's last attempt never starts a continuation: a
continuation it started would have nobody left to close it if it were
interrupted too. The last attempt closes the chain instead. A queued single
run's job is therefore given `2 + MaxResumeAttempts` attempts while
recovery is on: one for the run, one per continuation, and the last one
that closes the chain. A batch job keeps its own attempt limit
(`Tracon:Scheduling:MaxAttempts`, three by default, or the job's
`maxAttempts`) and gets at most two fewer continuations per item than
that limit: give it `2 + MaxResumeAttempts` attempts to get them all.
Must be from 0 to 100.

### <a id="Tracon_TraconWorkflowOptions_MaxRunTimeout"></a> MaxRunTimeout

Gets or sets the longest run timeout a workflow definition may set for itself
([WorkflowDefinition.RunTimeout](/api/tracon.workflowdefinition/#Tracon_WorkflowDefinition_RunTimeout)). [null](https://learn.microsoft.com/dotnet/csharp/language-reference/keywords/null) (the
default) means a definition may only shorten [TraconWorkflowOptions.RunTimeout](/api/tracon.traconworkflowoptions/#Tracon_TraconWorkflowOptions_RunTimeout).

```csharp
public TimeSpan? MaxRunTimeout { get; set; }
```

#### Property Value

 [TimeSpan](https://learn.microsoft.com/dotnet/api/system.timespan)?

#### Remarks

A running workflow holds one of the [TraconWorkflowOptions.MaxConcurrentRuns](/api/tracon.traconworkflowoptions/#Tracon_TraconWorkflowOptions_MaxConcurrentRuns) slots that
every tenant shares, so how long one run may hold it is the host's decision,
not the decision of whoever edits a definition. Set this to let some workflows
run longer than [TraconWorkflowOptions.RunTimeout](/api/tracon.traconworkflowoptions/#Tracon_TraconWorkflowOptions_RunTimeout) - a podcast chain whose writer step
takes several minutes, say - while every other workflow keeps the shorter
default.

A definition whose value is above the ceiling is refused when it is saved
(`400`). A stored definition whose value is above a ceiling that was
lowered later still runs, cut to the ceiling, and a warning is logged.

Must be from one millisecond to about 49.7 days, and not below
[TraconWorkflowOptions.RunTimeout](/api/tracon.traconworkflowoptions/#Tracon_TraconWorkflowOptions_RunTimeout); any other value fails at startup, whether or not
[TraconWorkflowOptions.Enabled](/api/tracon.traconworkflowoptions/#Tracon_TraconWorkflowOptions_Enabled) is on, because the ceiling guards a definition save.

```csharp
builder.AddTracon()
       .UseWorkflows(options =>
       {
           options.RunTimeout = TimeSpan.FromMinutes(10);
           options.MaxRunTimeout = TimeSpan.FromHours(1);
       });
```

### <a id="Tracon_TraconWorkflowOptions_MaxSuperSteps"></a> MaxSuperSteps

Gets or sets the maximum number of super-steps a single run may process.

```csharp
public int MaxSuperSteps { get; set; }
```

#### Property Value

 [int](https://learn.microsoft.com/dotnet/api/system.int32)

#### Remarks

This is the only structural guard against an infinite loop. In the
Handoff and GroupChat patterns the model decides when to hand off; a
poorly written instruction can make two agents hand off to each other
forever.

### <a id="Tracon_TraconWorkflowOptions_RequestExpirationScanInterval"></a> RequestExpirationScanInterval

Gets or sets how often the background scan looks for human requests whose time has run
out ([WorkflowDefinition.RequestTimeout](/api/tracon.workflowdefinition/#Tracon_WorkflowDefinition_RequestTimeout)) and closes their runs.

```csharp
public TimeSpan RequestExpirationScanInterval { get; set; }
```

#### Property Value

 [TimeSpan](https://learn.microsoft.com/dotnet/api/system.timespan)

#### Remarks

The default is one minute. A request is closed at most one interval after its time, so
a finer value only matters for a very short `RequestTimeout`. Only one instance of
a cluster scans at a time. The scan reads a partial index of the requests that have a
limit, so it costs nothing while no workflow sets one. Must be from one millisecond to
about 49.7 days.

### <a id="Tracon_TraconWorkflowOptions_ResumeInterruptedRuns"></a> ResumeInterruptedRuns

Gets or sets whether a workflow run that a queued job was running when the
process stopped is resumed from its latest checkpoint when the job is
leased again.

```csharp
public bool ResumeInterruptedRuns { get; set; }
```

#### Property Value

 [bool](https://learn.microsoft.com/dotnet/api/system.boolean)

#### Remarks

The default is [false](https://learn.microsoft.com/dotnet/csharp/language-reference/builtin-types/bool): an interrupted job item runs its
workflow again from the beginning, as before this setting existed. Turned
on, the job is the run's owner. It writes the run's id on the job item (for
a batch, `tracon.workflow`) before the run starts; a queued single run
(`Prefer: respond-async`, `tracon.workflow-run`) already has its
id as the job's id. When the job is leased again after a crash, a deploy or
a graceful shutdown, the handler finds that run and acts on its status:

- `Completed` or `AwaitingInput`: the work is done; nothing runs again.
- Any other status: a run left `Running` is closed as `Failed`, and a new run continues it from the latest checkpoint in its chain. The new run's `ContinuedFromRunId` names the run it continues; it uses the same session, the parameter values the chain recorded, and the attribution of whoever queued the job. It is not asked for quota or authorization again: the job was, when it was queued.
- No checkpoint in the chain: the run starts again from the beginning, or the resume or the response is applied again.

**The step that was running when the process stopped runs
again.** A checkpoint is written as each super-step ends, so the
steps finished before it are not repeated and the step in progress is. A
function step with a side effect must be idempotent, and an agent step
repeats its model calls and tool calls. A `Loop` agent step repeats
every turn it had finished: the loop's turns are not checkpointed.

A run that is bound to an HTTP connection (a streamed run) is never
resumed automatically: the caller who was reading it is gone, and the run
closes as `Canceled`. Resume it with the resume endpoint, or queue the
run with `Prefer: respond-async` in the first place.

Requires [TraconWorkflowOptions.EnableCheckpointing](/api/tracon.traconworkflowoptions/#Tracon_TraconWorkflowOptions_EnableCheckpointing): turning this on while
checkpointing is off fails at startup. A graceful shutdown closes the run
it stops as `Canceled` and keeps its checkpoints, also with
[TraconWorkflowOptions.KeepCheckpointsAfterCompletion](/api/tracon.traconworkflowoptions/#Tracon_TraconWorkflowOptions_KeepCheckpointsAfterCompletion) off; the continuation removes
them when it finishes.

```csharp
builder.AddTracon()
       .UsePostgreSql(connectionString)
       .UseWorkflows(options =>
       {
           options.ResumeInterruptedRuns = true;
           options.MaxResumeAttempts = 2;
       });
```

### <a id="Tracon_TraconWorkflowOptions_RunTimeout"></a> RunTimeout

Gets or sets the maximum duration of a single workflow run.

```csharp
public TimeSpan RunTimeout { get; set; }
```

#### Property Value

 [TimeSpan](https://learn.microsoft.com/dotnet/api/system.timespan)

#### Remarks

**Cooperative, and observed between super-steps.** The
deadline cancels the token the run is given, and the runner checks it
as each super-step ends; it does not abandon work already in flight.
A node that ignores its cancellation token therefore runs to
completion, and the run stops at the first boundary after it. Treat
this as a bound on how long a run keeps taking new steps, not as a
hard wall-clock limit.

A run stopped this way ends `Canceled` and reports a
`TimeoutException` error naming this setting. The deadline starts when
the run starts, so the time a run waits for a [TraconWorkflowOptions.MaxConcurrentRuns](/api/tracon.traconworkflowoptions/#Tracon_TraconWorkflowOptions_MaxConcurrentRuns)
slot counts too.

A workflow definition can set its own value
([WorkflowDefinition.RunTimeout](/api/tracon.workflowdefinition/#Tracon_WorkflowDefinition_RunTimeout)). It may only shorten this one
unless [TraconWorkflowOptions.MaxRunTimeout](/api/tracon.traconworkflowoptions/#Tracon_TraconWorkflowOptions_MaxRunTimeout) allows more. To bound one step instead,
give the node a timeout ([WorkflowNodeReference.Timeout](/api/tracon.workflownodereference/#Tracon_WorkflowNodeReference_Timeout), or
[WorkflowFunctionOptions.Timeout](/api/tracon.workflowfunctionoptions/#Tracon_WorkflowFunctionOptions_Timeout) when the function is
registered): a step that runs past it fails the run, and a function's token
is cancelled.

Must be from one millisecond to about 49.7 days while [TraconWorkflowOptions.Enabled](/api/tracon.traconworkflowoptions/#Tracon_TraconWorkflowOptions_Enabled)
is on; any other value fails at startup.
