Skip to content
Tracon

TraconWorkflowOptions

Namespace Tracon · Assembly Tracon.Workflows.dll

Settings that control workflow execution.

public sealed class TraconWorkflowOptions
Inheritance
object ← TraconWorkflowOptions
Inherited Members
object.GetType(), object.ToString(), object.Equals(object?), object.Equals(object?, object?), object.ReferenceEquals(object?, object?), object.GetHashCode()
public TraconWorkflowOptions()

The name of the configuration section.

public const string SectionName = "Tracon:Workflows"

string

Gets or sets whether checkpoint writing is enabled.

public bool EnableCheckpointing { get; set; }

bool

The default is true: resuming works out of the box. The cost is one write per super-step; TraconWorkflowOptions.MaxSuperSteps and the retention limit of the in-memory store keep this in check.

Gets or sets whether workflow execution is enabled.

public bool Enabled { get; set; }

bool

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

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

public bool KeepCheckpointsAfterCompletion { get; set; }

bool

The default is true: 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 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.

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

public int MaxConcurrentRuns { get; set; }

int

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.

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, and a run whose deadline passes before it gets a slot closes like any other timed-out run.

Gets or sets the most workflow runs one tenant may have going at the same time. null (the default) sets no per-tenant limit.

public int? MaxConcurrentRunsPerTenant { get; set; }

int?

Without it, one tenant that starts many runs holds every slot of 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, like the wait for a shared slot.

Must be from 1 to TraconWorkflowOptions.MaxConcurrentRuns; any other value fails at startup.

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

public int MaxNodeSettingsLength { get; set; }

int

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.

Gets or sets the most requests one scan closes (TraconWorkflowOptions.RequestExpirationScanInterval).

public int MaxRequestExpirationsPerScan { get; set; }

int

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

Gets or sets how many continuation runs one interrupted run may get while TraconWorkflowOptions.ResumeInterruptedRuns is on.

public int MaxResumeAttempts { get; set; }

int

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.

Gets or sets the longest run timeout a workflow definition may set for itself (WorkflowDefinition.RunTimeout). null (the default) means a definition may only shorten TraconWorkflowOptions.RunTimeout.

public TimeSpan? MaxRunTimeout { get; set; }

TimeSpan?

A running workflow holds one of the 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 - 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; any other value fails at startup, whether or not TraconWorkflowOptions.Enabled is on, because the ceiling guards a definition save.

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

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

public int MaxSuperSteps { get; set; }

int

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.

Gets or sets how often the background scan looks for human requests whose time has run out (WorkflowDefinition.RequestTimeout) and closes their runs.

public TimeSpan RequestExpirationScanInterval { get; set; }

TimeSpan

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.

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.

public bool ResumeInterruptedRuns { get; set; }

bool

The default is false: 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: 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 off; the continuation removes them when it finishes.

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

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

public TimeSpan RunTimeout { get; set; }

TimeSpan

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 slot counts too.

A workflow definition can set its own value (WorkflowDefinition.RunTimeout). It may only shorten this one unless TraconWorkflowOptions.MaxRunTimeout allows more. To bound one step instead, give the node a timeout (WorkflowNodeReference.Timeout, or 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 is on; any other value fails at startup.