Recover from an interrupted checkpoint¶
Resume a checkpoint that crashed during publish. The goal is one outcome: the workspace head advances exactly once, or not at all.
Publication is one atomic database transaction. A crashed publish either committed the new head or left the prior head unchanged. You never repair a partial head by hand. Recovery is idempotent retry: re-run the checkpoint with the same idempotency key, and the control plane returns the committed result for that key instead of duplicating work.
Detect¶
Watch for one or more of these signals:
- A checkpoint call returned an error, was cancelled, or its event stream
dropped before the
Resultevent. awcctl workspace status ws_01J...shows theheadandversionunchanged from before the attempt. The head references the complete prior snapshot or the complete new snapshot, never both.- The daemon restart reconciliation line reads
reconciled N session(s): renewed=... fenced=... deleted=... preserved=.... An interrupted checkpoint counts towardNbut not towardrenewed,fenced,deleted, orpreserved. The session is classCheckpointInterruptedorCleanupIncomplete. - The metric
awc_workspace_checkpoint_totalshows nooutcome="published"sample for the attempt (the interrupted stream, if any, countedoutcome="failed"). Requireshealth_http_listenon theawcdhost. - The file
checkpoint.jsonexists in the session state directory with aphaseother thanCOMPLETE.
Procedure¶
-
Capture the workspace id, the mount session id, and the current head and version.
Record
head,version, and the session id of the attempt. -
Read the persisted recovery record. The record is
checkpoint.jsonin the session state directory,<workspace_root>/<workspace-id>/<generation>/(defaultworkspace_rootis/var/lib/awc/workspaces).Read
phaseandidempotency_key. The phase tells you how far the attempt reached. Each phase maps to one recovery case:phaseReached Recovery action STARTEDIdentity recorded only Re-run construction, upload, then publish BUILTCandidate manifest persisted Re-run the closure upload, then publish UPLOADEDClosure durable Re-issue publication only PUBLISHEDHead already advanced Run post-publish cleanup only COMPLETEFully done Nothing to recover -
Confirm the writer lease still authorizes publication. Only an
ACTIVElease at the currentgenerationmay publish. If the lease isEXPIRED,REVOKED, or fenced by a higher generation, stop here. Follow Handle a stale writer. A stale fencing token MUST NOT publish. -
Restart the daemon to run restart reconciliation. The pass finishes post-publish cleanup for a
PUBLISHEDattempt and preserves the session for every earlier phase.The daemon never deletes an upper directory while the checkpoint state is uncertain.
-
Re-run the checkpoint with the same idempotency key. Pass the same session id and mode as the original attempt.
The re-run is safe for every phase. Immutable uploads are no-ops on objects already present, and the build is deterministic, so the re-run reproduces the same candidate.
-
Capture the result snapshot id and version.
If the original publish committed and only its response was lost, this re-run returns that same committed snapshot. The version does not advance a second time.
Verify¶
Confirm the head advanced exactly once:
awcctl workspace status ws_01J...showsheadequal to the result snapshot andversionexactly one higher than before the attempt.- The
checkpoint.jsonrecord now readsphase: COMPLETE. The attempt retired. awc_workspace_checkpoint_totalincremented once withoutcome="published", not twice. Requireshealth_http_listenon theawcdhost; otherwise confirm via thehead,version, andphasechecks above.- Mount the workspace and read back the checkpointed state. The merged view
equals
original lower + accumulated upper.
Impact¶
Uncheckpointed writes are not durable
If the crash happened before publication and you do not re-run the checkpoint, the upper delta stays local to the host. It is not remotely durable. A later host loss destroys it. The acknowledged head is whatever the last successful publish committed.
Current build: the daemon does not auto-resume a crashed publish
Restart reconciliation classifies an interrupted checkpoint
(CheckpointInterrupted, CleanupIncomplete) and finishes post-publish
cleanup. It does not re-issue publication. You MUST re-run
awcctl workspace checkpoint by hand. The library functions that decide
and drive the resume are implemented and unit-tested, but the live daemon
executor does not yet dispatch them.
Current build: CLI mounts have no writer lease
A checkpoint requires a writer lease. The call fails with
session has no writer lease when the session has no lease_id. Sessions
created by awcctl workspace mount do not yet carry one, so the recovery
re-run needs a session that the mount path issued a lease for.
The checkpoint counter needs the health listener
awc_workspace_checkpoint_total counts every terminal checkpoint event
with an outcome label (published, failed, cancelled). It renders
only when awcd runs with health_http_listen set. Without the listener,
detect and verify the recovery with the head and version values and the
checkpoint.json phase instead.
Publication is atomic
You cannot advance the head twice. The control plane completes every mutable update in one PostgreSQL transaction and deduplicates a repeated publish on the idempotency key. A retry either commits the new snapshot now or returns the one already committed.