Skip to content

Commit 28e26c0

Browse files
lambrospetrouOxyjun
authored andcommitted
SImplify the DO lifecycle and pricing docs to be clearer about idle hibernateable state (#24132)
* Update the DO lifecycle and pricing docs to be clearer about idle hibernateable state * Apply suggestions from code review * Updating image * Updating diagram * Update src/content/docs/durable-objects/concepts/durable-object-lifecycle.mdx --------- Co-authored-by: Jun Lee <[email protected]>
1 parent 8bfb2ba commit 28e26c0

File tree

3 files changed

+31
-45
lines changed

3 files changed

+31
-45
lines changed
544 KB
Loading

src/content/docs/durable-objects/concepts/durable-object-lifecycle.mdx

Lines changed: 26 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3,44 +3,34 @@ title: Lifecycle of a Durable Object
33
pcx_content_type: concept
44
sidebar:
55
order: 3
6-
76
---
87

98
import { Render, TypeScriptExample } from "~/components";
109

1110
This section describes the lifecycle of a [Durable Object](/durable-objects/concepts/what-are-durable-objects/).
1211

13-
To use a Durable Object you need to create a [Durable Object Stub](/durable-objects/api/stub/). In its simplest form, this looks like the following snippet:
12+
To use a Durable Object you need to create a [Durable Object Stub](/durable-objects/api/stub/).
13+
Simply creating the Durable Object Stub does not send a request to the Durable Object, and therefore the Durable Object is not yet instantiated.
14+
A request is sent to the Durable Object and its lifecycle begins only once a method is invoked on the Durable Object Stub.
1415

15-
```ts
16-
// Assume a DurableObjectNamespace binding MY_DURABLE_OBJECT
17-
// Every unique ID refers to an individual instance of the Durable Object class
16+
```js
1817
const id = env.MY_DURABLE_OBJECT.idFromName("foo");
1918
const stub = env.MY_DURABLE_OBJECT.get(id);
20-
```
21-
22-
Once we have the Durable Object Stub, we can now invoke methods on the Durable Object. Note that the above two lines do not yet send any request to the remote Durable Object.
23-
24-
The following line invokes the `sayHello()` method (which is an [RPC method](/durable-objects/best-practices/create-durable-object-stubs-and-send-requests/#invoke-rpc-methods)) of the Durable Object class bound to the `MY_DURABLE_OBJECT` binding:
25-
26-
```ts
27-
// All invoked methods need to be awaited.
19+
// Now the request is sent to the remote Durable Object.
2820
const rpcResponse = await stub.sayHello();
2921
```
3022

31-
At this point, the caller sends a request to the Durable Object identified by the stub. The lifecycle of the Durable Object begins.
32-
3323
## Durable Object Lifecycle state transitions
3424

3525
A Durable Object can be in one of the following states at any moment:
3626

37-
| State | Description |
38-
|--------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
39-
| **Active, in-memory** | The Durable Object runs, in memory, and handles incoming requests. |
27+
| State | Description |
28+
| ------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
29+
| **Active, in-memory** | The Durable Object runs, in memory, and handles incoming requests. |
4030
| **Idle, in-memory non-hibernateable** | The Durable Object waits for the next incoming request/event, but does not satisfy the criteria for hibernation. |
41-
| **Idle, in-memory hibernateable** | The Durable Object waits for the next incoming request/event and satisfies the criteria for hibernation. It is up to the runtime to decide when to hibernate the Durable Object. Currently, it is after 10 seconds of inactivity while in this state. |
42-
| **Hibernated** | The Durable Object is removed from memory. Hibernated WebSocket connections stay connected. |
43-
| **Inactive** | The Durable Object is completely removed from the host process and might need to cold start. This is the initial state of all Durable Objects. |
31+
| **Idle, in-memory hibernateable** | The Durable Object waits for the next incoming request/event and satisfies the criteria for hibernation. It is up to the runtime to decide when to hibernate the Durable Object. Currently, it is after 10 seconds of inactivity while in this state. |
32+
| **Hibernated** | The Durable Object is removed from memory. Hibernated WebSocket connections stay connected. |
33+
| **Inactive** | The Durable Object is completely removed from the host process and might need to cold start. This is the initial state of all Durable Objects. |
4434

4535
This is how a Durable Object transitions among these states (each state is in a rounded rectangle).
4636

@@ -52,26 +42,31 @@ At this point the Durable Object is in the **active in-memory state**.
5242

5343
If it continuously receives requests or events within 10 seconds of each other, the Durable Object will remain in this state.
5444

55-
After 10 seconds of no incoming request or events, the runtime can now hibernate the Durable Object. Hibernation will only occur if **all** of the below are true:
56-
- No `setTimeout`/`setInterval` scheduled callbacks are set.
57-
- No in-progress `fetch()` waiting for a remote request exists.
58-
- No WebSocket standard API is used.
59-
- No request/event is still being processed.
45+
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.
46+
47+
Hibernation can only occur if **all** of the conditions below are true:
6048

61-
If all conditions are met, the Durable Object will transition into a **hibernated** state.
49+
- No `setTimeout`/`setInterval` scheduled callbacks are set, since there would be no way to recreate the callback after hibernating.
50+
- No in-progress awaited `fetch()` exists, since it is considered to be waiting for I/O.
51+
- No WebSocket standard API is used.
52+
- No request/event is still being processed, because hibernating would mean losing track of the async function which is eventually supposed to return a response to that request.
53+
54+
After 10 seconds of no incoming request or event, and all the above conditions satisfied, the Durable Object will transition into the **hibernated** state.
6255

6356
:::caution
6457
When hibernated, the in-memory state is discarded, so ensure you persist all important information in the Durable Object's storage.
6558
:::
6659

67-
If any of the above conditions are false, the Durable Object remains in-memory, in the **idle, in-memory, non-hibernateable** state.
60+
If any of the above conditions is false, the Durable Object remains in-memory, in the **idle, in-memory, non-hibernateable** state.
6861

69-
In case of an incoming request or event while in the **hibernated** state, the `constructor()` will run again, and the corresponding function invoked will run.
62+
In case of an incoming request or event while in the **hibernated** state, the `constructor()` will run again, and the Durable Object will transition to the **active, in-memory** state and execute the invoked function.
7063

7164
While in the **idle, in-memory, non-hibernateable** state, after 70-140 seconds of inactivity (no incoming requests or events), the Durable Object will be evicted entirely from memory and potentially from the Cloudflare host and transition to the **inactive** state.
7265

73-
Objects in the **hibernated** state keep their Websocket clients connected, and the runtime decides if and when to move the object to a different host, thus restarting the lifecycle.
66+
Objects in the **hibernated** state keep their Websocket clients connected, and the runtime decides if and when to transition the object to the **inactive** state (for example deciding to move the object to a different host) thus restarting the lifecycle.
7467

7568
The next incoming request or event starts the cycle again.
7669

77-
As explained in [When does a Durable Object incur duration charges?](/durable-objects/platform/pricing/#when-does-a-durable-object-incur-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**.
70+
:::note[Lifecycle states incurring duration charges]
71+
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).
72+
:::

src/content/partials/durable-objects/do-faq-pricing.mdx

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,12 @@
44

55
### When does a Durable Object incur duration charges?
66

7-
A Durable Object incurs duration charges as long as the JavaScript object is held in memory. Once an object has been evicted from memory, the next time it is needed, it will be recreated (calling the constructor again). There are two factors which decide when an object may be evicted from memory: hibernatability and existence of clients.
7+
A Durable Object incurs duration charges as long as the JavaScript object has to be in memory, either because it is actively handling a request, or because it cannot hibernate.
88

9-
A Durable Object is considered hibernatable any time that it is not waiting for any I/O or callbacks that depend on the in-memory state.
9+
Once an object has been evicted from memory, the next time it is needed, it will be recreated (calling the constructor again).
1010

11-
- For example, if an object calls `fetch()` and awaits the response, it is considered to be waiting for I/O, and so cannot hibernate.
12-
13-
- Less obvious to a user, if an object calls `setTimeout()` to schedule a callback in the future - no matter how far in the future - then it is considered non-hibernatable, since there would be no way to recreate the callback after hibernating.
14-
15-
- Additionally, if the Durable Object has received an incoming request and has not fully responded yet, then it cannot be hibernated, because hibernating would mean losing track of the async function which is eventually supposed to return a response to that request.
16-
17-
- As an exception, a WebSocket request which has explicitly been accepted using the [WebSocket hibernation API](/durable-objects/best-practices/websockets/#websocket-hibernation-api) allows a Durable Object to hibernate even while the WebSocket is still connected.
18-
19-
Once a Durable Object has been in a hibernatable state for 10 consecutive seconds, it hibernates, and duration billing stops.
20-
21-
Even if a Durable Object never becomes hibernatable, it will still be evicted once all clients have gone away. A Durable Object is considered to have clients if any other Worker currently holds a stub pointing to the Durable Object, or is waiting for a response from the Durable Object. An incoming WebSocket connection counts as a client. If the object is currently responding to an alarm event, this also counts as having a client. When not hibernatable, a Durable Object will be evicted from memory after it has had no client for 70-140 seconds (the exact interval varies). But again, if the object is hibernatable, then the 10-second hibernation timeout takes precedence and the 70-140 second no-client timeout is moot.
11+
There are several factors that contribute in keeping the Durable Object in memory and keeping it from hibernating or being inactive.
12+
Find more information in [Lifecycle of a Durable Object](/durable-objects/concepts/durable-object-lifecycle/).
2213

2314
### Does an empty table / SQLite database contribute to my storage?
2415

@@ -28,4 +19,4 @@ Yes, although minimal. Empty tables can consume at least a few kilobytes, based
2819

2920
All writes to a SQLite-backed Durable Object stores nominal amounts of metadata in internal tables in the Durable Object, which counts towards your billable storage.
3021

31-
The metadata remains in the Durable Object until you call [`deleteAll()`](/durable-objects/api/storage-api/#deleteall).
22+
The metadata remains in the Durable Object until you call [`deleteAll()`](/durable-objects/api/storage-api/#deleteall).

0 commit comments

Comments
 (0)