Ship a Restart-Safe Upload CLI That Survives an Expired Resume URL
My upload CLI looked restart-safe until I tested two failures together: the process crashed at 63%, and the signed resume URL expired before restart.
Checkpoint Structure
The checkpoint needs identity, not credentials:
{ "file" : "release.tar.gz" , "fingerprint" : "sha256:..." , "uploadId" : "up_123" , "localOffset" : 66060288 , "updatedAt" : "2026-07-19T12:00:00Z" }
Do not persist the signed URL.
Recovery Logic
On restart, exchange the durable upload ID for fresh authorization, query the server offset, then reconcile:
const remote = await headUpload ( freshUrl );
if ( remote > file . size ) throw new Error ( " invalid remote offset " );
if ( remote !== checkpoint . localOffset ) {
await saveCheckpoint ({ ... checkpoint , localOffset : remote });
}
await sendFrom ( file , remote , freshUrl );
The server offset wins because a crash can occur after bytes are accepted but before the local checkpoint is renamed. Save checkpoints through write-to-temp plus atomic rename so a partial JSON file cannot destroy recovery.
Failure Fixture Matrix
My fixture matrix includes:
| Failure | Expected behavior |
|---|---|
| crash after remote commit | rewind/advance to remote offset |
| expired URL | refresh without creating a second upload |
| changed local file | stop on fingerprint mismatch |
| missing remote upload | ask before starting over |
| checkpoint write interrupted | retain previous valid checkpoint |
Protocol and Design Principles
The tus resumable upload protocol specifies offset discovery and conflict handling that are useful even if the service uses a smaller custom protocol. The key idea is explicit reconciliation, not assuming client memory is authoritative.
User-Facing Recovery Features
I also shipped upload status, upload forget, and an exportable checkpoint directory. Recovery is a user-facing feature; if users cannot inspect or remove state, βresumableβ becomes hidden lock-in.
Comments
No comments yet. Start the discussion.