Skip to main content

Flow options

Dex allows you to customize the behavior of a Flow execution.

  • StartFlowOptions apply when a client starts a Flow (or SubFlow). They are immutable after start.
    • They control timeout, ID reuse, initial Attributes, request idempotency, and optional config overrides for that execution.
  • FlowConfig provide runtime behavior. They are mutable after start.
    • Step durability defaults, Worker routing, active-Step search indexing, continue-as-new thresholds, and Attribute Store projection targets.

StartFlowOptions

FieldPurpose
TimeoutFlow timeout. Omit it or set zero to disable it.
TimeoutPolicyWhat happens when the flow timeout fires.
TimeoutHandlerOptionsExecution, retry, recovery, durability, locking, and state loading for a timeout handler.
IDReusePolicyHow to reuse existing Flow ID to start
RequestIDIdempotency key for retrying one start request.
AlreadyStartedOptionsHow to handle an already-started Flow.
RetryPolicyRetry policy for one Flow execution after failure.
StartDelayDelay before the start Step to run.
AttributesInitial Attribute values.
FlowConfigPer-execution Flow configuration

For an application-defined outcome at the Flow deadline, see Graceful Timeout.

def example_start_flow_options() -> StartFlowOptions:
return StartFlowOptions(
timeout=timedelta(minutes=30),
timeout_policy=FlowTimeoutPolicy.HANDLER,
start_delay=timedelta(minutes=5),
id_reuse_policy=IdReusePolicy.DISALLOW,
retry_policy=RetryPolicy(
initial_interval=timedelta(minutes=1),
backoff_coefficient=2,
maximum_interval=timedelta(minutes=10),
maximum_attempts=3,
),
config_override=FlowConfig(step_durability=StepDurability.SYNC),
ignore_already_started=True,
request_id="start-order-123",
).with_attribute(status, "queued")

Example: examples/python/dex_examples/primitives/flow/controller.py

Timeout and TimeoutPolicy

Timeout is one durable timer for the whole Flow. Set TimeoutPolicy only when Timeout is positive.

  • FAIL — fail the Flow with a timeout error. RetryPolicy can retry it.
  • CANCEL — cancel the Flow. It does not retry.
  • HANDLER — run one logical Flow timeout-handler execution.

With a positive Timeout, a Dex SDK uses FAIL by default. If the Flow has a timeout handler, it uses HANDLER instead. HANDLER is invalid when the Flow has no handler. A retry starts with a new timeout budget.

TimeoutHandlerOptions is valid only with a positive Timeout and a final HANDLER policy. It uses Execute semantics: a method timeout limits each attempt, Retry can run multiple attempts, HeartbeatTimeout detects stalled regular attempts, and Failure can route exhausted retries to a registered no-input Step. The recovery Step receives null or unit input and reads the final error from the handler Context.

The handler's attempt and retry clocks begin when the soft Flow timeout fires. They may extend past the original Flow deadline. If no failure target is configured, an exhausted handler fails the Flow.

Ordinary Attributes and all Channel size metadata load automatically. AttributeMap values and pending Channel messages require explicit selections in TimeoutHandlerOptions. The handler may stage Attribute writes, Channel deletions, and Channel publications before returning its decision. Continue-as-new and Flow retries preserve the options; a Flow retry starts a new soft-timeout budget.

Set TimeoutPolicy to HANDLER to run this code when the timeout fires. This handler records why the Flow ended, then fails it with an application reason.

def handle_timeout(self, context: Context) -> StepDecision:
status.set(context, "timed out")
return force_fail("processing deadline reached")

Example: examples/python/dex_examples/primitives/flow/example_flow.py

Flow ID, RequestID, and AlreadyStartedOptions

IDReusePolicy says what to do when this Flow ID already exists. RequestID says whether this call retries the same start request.

How these options work together

These options answer different questions, in this order:

  1. RequestID identifies one start request. When omitted, the SDK generates a new UUID, so another StartFlow call is a new request. Reuse it only for a retry of the exact same start. Dex compares the RequestID, not the start input or options.
  2. IDReusePolicy decides whether that request may start another run with this Flow ID.
  3. AlreadyStartedOptions.IgnoreError matters only when the ID reuse policy rejects the start as already started. It returns the existing Run ID only when the RequestID matches.
Retry requestAlreadyStartedOptions.IgnoreErrorWhen the ID reuse policy rejects the start
No RequestID, or a new RequestIDOff or onThe SDK sends a new UUID. Dex returns an already-started error.
Same RequestIDOffDex returns an already-started error.
Same RequestIDOnDex returns the existing Run ID.

The ID reuse policy determines whether Dex rejects the start in the first place:

IDReusePolicyExisting active FlowExisting closed Flow
IDReuseDefaultRejects the start. A matching RequestID with IgnoreError returns the active Run ID.Starts a new run.
IDReuseAllowIfPreviousFailedRejects the start. A matching RequestID with IgnoreError returns the active Run ID.Starts a new run only after a failed run; otherwise rejects it.
IDReuseAllowIfNotRunningRejects the start. A matching RequestID with IgnoreError returns the active Run ID.Starts a new run.
IDReuseDisallowRejects the start. A matching RequestID with IgnoreError returns the existing Run ID.Rejects the start. A matching RequestID with IgnoreError returns the existing Run ID.
IDReuseTerminateIfRunningTerminates the active run and starts a replacement. It does not produce an already-started error.Starts a new run.

What Dex Server does

Dex Server requires a non-empty RequestID. An SDK generates one before sending the request when you omit it. The server records it with the Flow execution, then asks the configured backend to start the Flow using the requested ID reuse policy. IDReuseDefault uses the server default: start a new Flow execution when no execution is active.

If the backend reports that the Flow is already started, Dex checks AlreadyStartedOptions.IgnoreError. When it is on, Dex reads the existing run's recorded RequestID. It returns that Run ID only when the two RequestIDs match. Otherwise it returns the already-started error.

RetryPolicy

RetryPolicy retries one Flow execution after it fails. MaximumAttempts includes the first execution. InitialInterval, BackoffCoefficient, and MaximumInterval set the exponential backoff. A FAIL timeout can use this retry policy. A CANCEL timeout cannot.

StartDelay

StartDelay accepts the Flow to start now, but waits before the StartStep can run. Use it for a one-off delay, for example, wait five minutes before processing a new order. Use a durable Timer loop for recurring work.

Attributes

Attributes write initial values . Each value must match an Attribute or Attribute map in the Flow persistence schema.

FlowConfig

Use ConfigOverride in StartFlowOptions to change the initial configuration for one Flow. It changes only the fields you provide. It does not replace the whole FlowConfig.

At start, Dex applies the supplied fields over the Dex Server defaults. Omitted fields keep their default values.

FieldBehavior
ActiveStepSearchModeIndex every active Step, only Steps that ran WaitFor, or no active Steps. The default indexes Steps with WaitFor.
ContinueAsNewThresholdContinue as new after this many tracked events. Zero turns it off.
ContinueAsNewPageSizeBytesLimit each page of state carried into continue-as-new. Zero uses 1 MiB.
StepDurabilityDefault durability for methods without a Step override. Dex resolves a method override first, then this value, then SYNC.
WorkerTargetWorkerService endpoint for Step and RPC invocation
AttributeStoreNamesDex Server Attribute Stores for Attributes that opt in to attribute sync

Update FlowConfig with a Client

Call UpdateFlowConfig while the Flow is active. Send only the fields you want to change.They will be merged with the existing configuration.