diff --git a/src/content/docs/durable-objects/concepts/durable-object-lifecycle.mdx b/src/content/docs/durable-objects/concepts/durable-object-lifecycle.mdx index 4369eec3c6f4fae..dae14d42c773dae 100644 --- a/src/content/docs/durable-objects/concepts/durable-object-lifecycle.mdx +++ b/src/content/docs/durable-objects/concepts/durable-object-lifecycle.mdx @@ -39,7 +39,6 @@ Assuming a Durable Object does not run, the first incoming request or event (lik At this point the Durable Object is in the **active in-memory state**. - Once all incoming requests or events have been processed, the Durable Object remains idle in-memory for a few seconds either in a hibernateable state or in a non-hibernateable state. Hibernation can only occur if **all** of the conditions below are true: @@ -68,3 +67,46 @@ The next incoming request or event starts the cycle again. :::note[Lifecycle states incurring duration charges] A Durable Object incurs charges only when it is **actively running in-memory**, or when it is **idle in-memory and non-hibernateable** (indicated as green rectangles in the diagram). ::: + +## Shutdown behavior + +Durable Objects may occasionally shut down and be replaced with a new instance. This can happen for various reasons, including: + +- New deployments with code updates +- Updates to the Workers runtime system +- The runtime deciding to move the Durable Object to a different host + +When a Durable Object is shut down, a new instance will come up automatically to handle new requests In-flight requests are handled as follows: + +- **HTTP requests**: Requests are allowed to finish for up to 30 seconds. However, if a request attempts to access storage during this grace period, it will be stopped immediately, since storage access is now occurring on the new instance. +- **WebSocket connections**: WebSocket requests are terminated automatically during shutdown. This is so that the new instance can take over the connection as soon as possible. +- **Other invocations (email, cron)**: Other invocations are treated similarly to HTTP requests. + +It is important to ensure that any services using Durable Objects are designed to handle the possibility of a Durable Object being shut down. + +### Code updates + +When your Durable Object code is updated, your Worker and Durable Objects are released globally in an eventually consistent manner. This will cause a Durable Object to shut down, with the behavior described above. Updates can also create a situation where a request reaches a new version of your Worker in one location, and calls to a Durable Object still running a previous version elsewhere. Refer to [Code updates](/durable-objects/platform/known-issues/#code-updates) for more information about handling this scenario. + +### Working without shutdown hooks + +Durable Objects do not provide shutdown hooks or lifecycle callbacks that run before shutdown. This is because Cloudflare cannot guarantee these hooks would execute in all cases, and external software may rely too heavily on these (unreliable) hooks. + +Instead of relying on shutdown hooks, you can regularly write to storage to recover gracefully from shutdowns. + +For example, if you are processing a stream of data and need to save your progress, write your position to storage as you go rather than waiting to persist it at the end: + +```js +// Good: Write progress as you go +async processData(data) { + data.forEach(async (item, index) => { + await this.processItem(item); + // Save progress frequently + await this.ctx.storage.put("lastProcessedIndex", index); + }); +} +``` + +While this may feel unintuitive, Durable Object storage writes are fast and synchronous, so you can persist state with minimal performance concerns. + +This approach ensures your Durable Object can safely resume from any point, even if it shuts down unexpectedly.