Invental/Review lessons/Writes that span systems

Writes that span systems

Stage, commit, then delete old files

When a write spans a database and object storage, order it so every crash point leaves a recoverable state: stage the new object, commit the row, then delete the old object after the commit. Never delete before the commit.

01 · Before and afterThe pattern

TypeScript
// before: delete happens inside the operation; a crash or later failure orphans or breaks references
await storage.move(oldKey, newKey); await db.update(doc, { key: newKey })
// after: stage -> commit -> cleanup
await storage.copy(oldKey, newKey); stage.track(newKey)       // rolled back if anything below throws
await db.transaction(tx => tx.update(doc, { key: newKey }))
afterCommit(() => storage.deleteIfUnreferenced(oldKey))      // only once nothing points at it

02 · Run it on your appThe check

If your server crashes between the file upload and the database save, which of the two is left pointing at nothing?

If the honest answer is no or not sure, this is worth a look before it reaches production.

Want this checked on your code?

Tell us what you are building and what worries you. We match a senior reviewer to your code and confirm scope before anything starts.

— Get in touch
hi@invental.co ↗
— Or
— What to include

A link or short description of the code or system, what you want checked, your stack, and when you need the answer. No repository access is needed until scope is agreed.

— Or leave a note
We reply within one business day.