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.
The checkpoint needs identity, not credentials:
{
"file": "release.tar.gz",
"fingerprint": "sha256:...",
"uploadId": "up_123",
"localOffset": 66060288,
"updatedAt": "2026-07-19T12:00:00Z"
}
Enter fullscreen mode Exit fullscreen mode
Do not persist the signed URL. 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);
Enter fullscreen mode Exit fullscreen mode
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.
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 checkpointThe 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.
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.
답글 남기기