Skip to content

An object's state and queued work survive a crash, a deploy or a move to another worker, and pick up where they left off.

Trays are actors inside your object. Each tray has its own durable state and an inbox: awaiting a send returns once the message is in the store, and the tray handles its messages one at a time, from the head of its queue. A message is gone only when its handler returns and the removal is written, so if the worker dies, another worker reopens the tray and redelivers what was unfinished, with ctx.attempts marking the retry. No workflow engine and no replay log: the handler simply runs again. An object can hold many trays, one per queue or one per key.

A tray. Your route sends a message to the tray's inbox, which writes it to the state store. The handler takes messages from the head of the inbox one at a time; when it returns, the message's removal and any state changes are written to the store.TrayYour routeInboxqueued messagesHandlerone at a timeState storePostgressendpersistack, statehead
Durable execution in four steps. One: Pinboard forwards a request to worker-1, which admits work into the object's tray. Two: worker-1 writes the pending item to the state store, then crashes. Three: Pinboard places the id on worker-2. Four: worker-2 restores the tray from the state store and resumes the unfinished work.Pinboardrouterworker-1crasheddownworker-2new ownerownerState storePostgres1enqueue2pending item3re-place4restore, resume

The whole durable object, one tray and a route that admits work, with a Postgres store shared by every worker: