Signal & Context
← Back to the reading room

Engineering

A resumable agent needs safe side effects

Saving progress helps an interrupted workflow continue, but external actions need their own identity and confirmation.

On this page

An interrupted publication has two states

A workflow can remember that it is about to publish while the destination has already accepted the publication. Resuming from that checkpoint may repeat an external action. LangGraph's persistence documentation describes saved graph state and information that survives runs; it does not make an unrelated destination's action receipt part of the same transaction.

Our static publisher provides a concrete way to reason about this boundary without sending a message or payment. The retained November 6 release record says the three publications moved from version r27 to r28. Before switching, the publisher checked the expected predecessor, archive identity and every staged file. It held a shared publication lock and used an atomic version-pointer change. The operation succeeded with retained destination readbacks. This was a website release, not a LangGraph deployment or an interrupted-agent benchmark.

Write down the intended action

For a recovery exercise, use three symbolic versions: A is the expected predecessor, B is this job's candidate and C is a different publisher's later version. Keep the action's identity separate from the workflow's current step. A minimal record might be:

  • Action: publish-release-B.
  • Expected predecessor: A.
  • Candidate artifact: B, identified by its full manifest digest.
  • Destination: the existing publication.
  • Receipt: unknown after connection loss.

This is an illustrative record, not a runnable configuration format. The missing receipt is the condition to investigate. It is not evidence that the destination rejected the action.

Resolve the ambiguity before repeating the request

  • The destination still points at A. Verify that no B result exists and that the candidate and authorization remain valid. Reacquire the lock and recheck A immediately before attempting the switch. An old observation of A does not reserve the destination.
  • The destination points at B and its bytes match. Reconstruct the completion record from the destination observation. Do not publish a second copy merely because the worker missed the first receipt.
  • The destination points at C. Another publication has intervened. Stop and reconcile ownership. Replacing C with A as a generic rollback would undo someone else's work.
  • The destination cannot be inspected. Retain an unknown status and request reconciliation. Repeatedly creating new action identities can turn a temporary uncertainty into duplicate external effects.

These four branches are a proposed failure exercise, not four failures we induced in production. The actual project publisher implements a related protection: its error handler restores an earlier pointer only if the current pointer still belongs to the version it just activated. That ownership condition matters as much as keeping an old copy.

A lock and a checkpoint solve different problems

The lock coordinates publishers using this deployment path. It does not cover an administrator changing the destination outside it. The manifest identifies files; it does not prove that readers received a correct page. A checkpoint records workflow progress; it does not certify a remote side effect. Destination-specific idempotency support, when available, has its own rules and should be used with the same stable action identity.

For email, payment or social publishing, identify the destination's actual receipt and lookup operation before designing automatic retries. This article does not claim that those services were connected. Start in a disposable test environment and interrupt before the send, after the send but before local recording, and after the receipt. For each case, inspect whether exactly one intended object exists and whether the recovery path can establish that fact.

The operational decision

Resume the preparation work freely when it has no external effect. Resume a consequential action only after resolving the destination state or applying a documented idempotent operation. When the state remains unknown, preserve that uncertainty. The goal is one authorized result with a traceable receipt, not a workflow that always reaches a success label.

Suggest a correction

Continue reading