Durable AI Workflows in .NET: Checkpoints, Human Approval, Recovery, and Idempotency

6 minute read

Published:

Long-running AI work cannot depend on one process, connection, or conversation remaining alive. Microsoft Agent Framework workflows provide explicit executors and edges, checkpointing can resume an in-process workflow model, and the Durable Extension can persist execution across distributed workers. Reliability still depends on application-owned identities, idempotent side effects, versioned state, and precise approval boundaries.

Use a workflow when the path matters

An agent is useful when the model should choose what to do next. A workflow is better when the business requires known stages, ordering, branching, or approval.

collect evidence
  -> draft recommendation
  -> deterministic policy checks
  -> human approval
  -> execute one bounded action
  -> verify and close

Agents can operate inside selected stages. Code should own the graph whenever skipping or reordering a stage would violate policy.

Model work as typed executors and edges

Keep each executor responsible for one transition with a typed input and output. Separate model reasoning from deterministic validation and side effects.

WorkflowBuilder workflowBuilder = new(collectEvidence);
workflowBuilder.AddEdge(collectEvidence, draftRecommendation);
workflowBuilder.AddEdge(draftRecommendation, validatePolicy);
workflowBuilder.AddEdge(validatePolicy, requestApproval);
workflowBuilder.AddEdge(requestApproval, executeAction);

Workflow workflow = workflowBuilder.Build();

Agent Framework APIs evolve, so pin package versions and keep workflow construction in an infrastructure adapter. Domain commands and state should remain application-owned types.

Understand superstep boundaries

Workflows execute triggered nodes in coordinated supersteps. A checkpoint at a completed boundary can capture messages, shared state, iteration count, and pending requests consistently.

Parallel branches in the same superstep synchronize before the workflow advances. Design fan-out with that behavior in mind. One long branch can delay the next stage even when another branch finished quickly.

Checkpoint meaningful progress

Checkpointing prevents completed reasoning or data collection from being repeated after a recoverable failure.

CheckpointManager checkpointManager =
    CheckpointManager.CreateInMemory();

StreamingRun run = await InProcessExecution.RunStreamingAsync(
    workflow,
    input,
    checkpointManager);

await foreach (WorkflowEvent workflowEvent in run.WatchStreamAsync())
{
    if (workflowEvent is SuperStepCompletedEvent completed)
    {
        CheckpointInfo? checkpoint = completed.CompletionInfo?.Checkpoint;
        // Persist the checkpoint reference with trusted ownership metadata.
    }
}

An in-memory checkpoint is useful for development, not process recovery. Production storage needs encryption, retention, concurrency control, and partitioning by authenticated tenant and subject.

Distinguish checkpointing from distributed durability

Standard workflow checkpoints resume state through the Agent Framework runtime. The Durable Extension runs agents and graph-based workflows on Durable Task infrastructure so progress can survive process restarts and execute across durable workers.

Choose the simpler mechanism that meets recovery requirements. A short interactive workflow may need only checkpoint storage; a multi-hour process with timers, external events, or worker restarts needs a durable execution model.

Bind human approval to exact intent

An approval request must present an immutable summary of what will happen:

  • action type and target
  • tenant and caller
  • important arguments and amount
  • evidence and policy result
  • expiration and approval identifier

Persist a hash of the proposed command. After approval, compare the command again before execution. Approval of one refund must not authorize a later amount, target, or reason generated by another model turn.

Authorize workflow continuation

Checkpoint IDs, request IDs, context IDs, and task IDs are untrusted external inputs when a client sends them back. Authenticate the caller, load state from the caller’s partition, and authorize access before resuming.

Never use a globally guessable checkpoint ID as a bearer credential. Audit continuation, denial, expiration, cancellation, and reassignment decisions.

Make every side effect idempotent

The workflow engine, transport, or operator may retry after an uncertain failure. Write steps need a stable operation ID stored with the business result.

public sealed record ApprovedAction(
    Guid OperationId,
    string ApprovalId,
    string ProposalHash,
    Guid TargetId);

If OperationId already completed, return the original result. If the same ID arrives with different arguments, reject it. Idempotency belongs in the target business service, not only in workflow memory.

Separate retry, compensation, and repair

A retry repeats an operation expected to be safe. Compensation performs a new business action to reduce the effect of a completed step. Repair asks an operator to resolve state that automation cannot safely reconcile.

Document which category applies to every side effect. Do not call a compensating payment or account operation automatically unless the business has explicitly defined and tested that behavior.

Version durable state

A workflow may resume after application code has changed. Persist a workflow definition version, prompt and model version, tool schema version, and serialized-state version.

Use additive state changes where possible and provide migration or compatibility handlers for active runs. Deploying a graph that removes an executor referenced by saved state can make existing work impossible to resume.

Bound workflow execution

Set limits for elapsed time, iterations, model turns, tool calls, parallel branches, tokens, cost, and recovery attempts. Cancellation should propagate to active model and tool calls while leaving durable state consistent.

Define terminal states such as completed, rejected, cancelled, expired, failed-repairable, and failed-final. “Still running” should not become the default outcome for an abandoned approval.

Observe the complete history

Correlate workflow ID, trusted owner, definition version, executor transitions, model calls, tool operations, approvals, checkpoints, retries, and final business result. Protect prompt and tool content through redaction and access control.

Alerts should focus on stuck approvals, repeated executor failures, checkpoint persistence errors, recovery loops, and side-effect conflicts.

Test crash and resume behavior

Integration tests should terminate execution after each meaningful boundary, recreate the host, resume from durable state, and verify that completed actions are not repeated.

Also test approval expiry, changed arguments, duplicate responses, concurrent continuation, incompatible state versions, cancellation during streaming, tool timeout, and storage unavailability.

Common mistakes to avoid

Watch for these issues:

  • using an open-ended agent loop for a policy-ordered process
  • assuming an in-memory checkpoint provides durability
  • treating checkpoint or task IDs as authorization
  • approving a description that is not bound to exact arguments
  • relying on workflow state instead of business-level idempotency
  • retrying compensating or irreversible operations automatically
  • deploying graph changes without active-state compatibility
  • restoring execution without testing process termination

Durable AI workflows combine model reasoning with deterministic control. The graph owns order, checkpoints preserve progress, humans approve exact intent, and business services make repeated execution safe.


Next Article: Production MCP Servers with ASP.NET Core: HTTP Transport, OAuth, Authorization, and Tool Auditing