Skip to content

Commit ee7e2f9

Browse files
committed
Clarify Durable Objects duration billing
1 parent 6062a7d commit ee7e2f9

File tree

2 files changed

+63
-18
lines changed

2 files changed

+63
-18
lines changed

src/content/docs/durable-objects/platform/pricing.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ The metadata remains in the Durable Object until you call [`deleteAll()`](/durab
142142

143143
### When does a Durable Object incur duration charges?
144144

145-
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.
145+
A Durable Object incurs duration charges as long as the JavaScript object is not able to be evicted from 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.
146146

147147
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.
148148

@@ -154,6 +154,6 @@ A Durable Object is considered hibernatable any time that it is not waiting for
154154

155155
- 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.
156156

157-
Once a Durable Object has been in a hibernatable state for 10 consecutive seconds, it hibernates, and duration billing stops.
157+
Duration billing stops once a Durable Object is in a hibernatable state. When a Durable Object has been in a hibernatable state for 10 consecutive seconds, it hibernates.
158158

159159
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.

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

Lines changed: 61 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,13 @@ params:
33
- product
44
---
55

6-
import { Render, Markdown, GlossaryTooltip, Details, AnchorHeading } from "~/components";
6+
import {
7+
Render,
8+
Markdown,
9+
GlossaryTooltip,
10+
Details,
11+
AnchorHeading,
12+
} from "~/components";
713

814
{ props.product === "durable-objects" && <><AnchorHeading title="Compute billing" depth={2}/></> }
915
{ props.product === "workers" && <><AnchorHeading title="Compute billing" depth={3}/></> }
@@ -17,7 +23,11 @@ Durable Objects are billed for duration while the Durable Object is active and r
1723

1824
<Details header="Footnotes" open={true}>
1925

20-
<sup>1</sup> Each [RPC session](/workers/runtime-apis/rpc/lifecycle/) is billed as one request to your Durable Object. Every [RPC method call](/durable-objects/best-practices/create-durable-object-stubs-and-send-requests/) on a [Durable Objects stub](/durable-objects/) is its own RPC session and therefore a single billed request.
26+
<sup>1</sup> Each [RPC session](/workers/runtime-apis/rpc/lifecycle/) is billed
27+
as one request to your Durable Object. Every [RPC method
28+
call](/durable-objects/best-practices/create-durable-object-stubs-and-send-requests/)
29+
on a [Durable Objects stub](/durable-objects/) is its own RPC session and
30+
therefore a single billed request.
2131

2232
RPC method calls can return objects (stubs) extending [`RpcTarget`](/workers/runtime-apis/rpc/lifecycle/#lifetimes-memory-and-resource-management) and invoke calls on those stubs. Subsequent calls on the returned stub are part of the same RPC session and are not billed as separate requests. For example:
2333

@@ -28,13 +38,34 @@ await foo.baz(); // treated as part of the same RPC session created by calling b
2838
await durableObjectStub.cat(); // billed as a request
2939
```
3040

31-
<sup>2</sup> A request is needed to create a WebSocket connection. There is no charge for outgoing WebSocket messages, nor for incoming [WebSocket protocol pings](https://www.rfc-editor.org/rfc/rfc6455#section-5.5.2). For compute requests billing-only, a 20:1 ratio is applied to incoming WebSocket messages to factor in smaller messages for real-time communication. For example, 100 WebSocket incoming messages would be charged as 5 requests for billing purposes. The 20:1 ratio does not affect Durable Object metrics and analytics, which reflect actual usage.
32-
33-
<sup>3</sup> Application level auto-response messages handled by [`state.setWebSocketAutoResponse()`](/durable-objects/best-practices/websockets/) will not incur additional wall-clock time, and so they will not be charged.
34-
35-
<sup>4</sup> Duration is billed in wall-clock time as long as the Object is active, but is shared across all requests active on an Object at once. Calling `accept()` on a WebSocket in an Object will incur duration charges for the entire time the WebSocket is connected. It is recommended to use the WebSocket Hibernation API to avoid incurring duration charges once all event handlers finish running. Note that the Durable Object will remain active for 10 seconds after the last client disconnects. For a complete explanation, refer to [When does a Durable Object incur duration charges?](/durable-objects/platform/pricing/#when-does-a-durable-object-incur-duration-charges).
36-
37-
<sup>5</sup> Duration billing charges for the 128 MB of memory your Durable Object is allocated, regardless of actual usage. If your account creates many instances of a single Durable Object class, Durable Objects may run in the same isolate on the same physical machine and share the 128 MB of memory. These Durable Objects are still billed as if they are allocated a full 128 MB of memory.
41+
<sup>2</sup> A request is needed to create a WebSocket connection. There is no
42+
charge for outgoing WebSocket messages, nor for incoming [WebSocket protocol
43+
pings](https://www.rfc-editor.org/rfc/rfc6455#section-5.5.2). For compute
44+
requests billing-only, a 20:1 ratio is applied to incoming WebSocket messages to
45+
factor in smaller messages for real-time communication. For example, 100
46+
WebSocket incoming messages would be charged as 5 requests for billing purposes.
47+
The 20:1 ratio does not affect Durable Object metrics and analytics, which
48+
reflect actual usage.
49+
50+
<sup>3</sup> Application level auto-response messages handled by
51+
[`state.setWebSocketAutoResponse()`](/durable-objects/best-practices/websockets/)
52+
will not incur additional wall-clock time, and so they will not be charged.
53+
54+
<sup>4</sup> Duration is billed in wall-clock time as long as the Object is
55+
active, but is shared across all requests active on an Object at once. Calling
56+
`accept()` on a WebSocket in an Object will incur duration charges for the
57+
entire time the WebSocket is connected. It is recommended to use the WebSocket
58+
Hibernation API to avoid incurring duration charges once all event handlers
59+
finish running. For a complete explanation, refer to [When does a Durable Object
60+
incur duration
61+
charges?](/durable-objects/platform/pricing/#when-does-a-durable-object-incur-duration-charges).
62+
63+
<sup>5</sup> Duration billing charges for the 128 MB of memory your Durable
64+
Object is allocated, regardless of actual usage. If your account creates many
65+
instances of a single Durable Object class, Durable Objects may run in the same
66+
isolate on the same physical machine and share the 128 MB of memory. These
67+
Durable Objects are still billed as if they are allocated a full 128 MB of
68+
memory.
3869

3970
</Details>
4071

@@ -59,15 +90,21 @@ The [Durable Objects Storage API](/durable-objects/api/storage-api/) is only acc
5990

6091
<Details header="Footnotes" open={true}>
6192

62-
<sup>1</sup> Rows read and rows written included limits and rates match [D1 pricing](/d1/platform/pricing/), Cloudflare's serverless SQL database.
93+
<sup>1</sup> Rows read and rows written included limits and rates match [D1
94+
pricing](/d1/platform/pricing/), Cloudflare's serverless SQL database.
6395

64-
<sup>2</sup> Key-value methods like `get()`, `put()`, `delete()`, or `list()` store and query data in a hidden SQLite table and are billed as rows read and rows written.
96+
<sup>2</sup> Key-value methods like `get()`, `put()`, `delete()`, or `list()`
97+
store and query data in a hidden SQLite table and are billed as rows read and
98+
rows written.
6599

66100
<sup>3</sup> Each `setAlarm()` is billed as a single row written.
67101

68102
<sup>4</sup> Deletes are counted as rows written.
69103

70-
<sup>5</sup> Durable Objects will be billed for stored data until the [data is removed](/durable-objects/best-practices/access-durable-objects-storage/#remove-a-durable-objects-storage). Once the data is removed, the object will be cleaned up automatically by the system.
104+
<sup>5</sup> Durable Objects will be billed for stored data until the [data is
105+
removed](/durable-objects/best-practices/access-durable-objects-storage/#remove-a-durable-objects-storage).
106+
Once the data is removed, the object will be cleaned up automatically by the
107+
system.
71108

72109
</Details>
73110

@@ -83,15 +120,23 @@ The [Durable Objects Storage API](/durable-objects/api/storage-api/) is only acc
83120

84121
<Details header="Footnotes" open={true}>
85122

86-
<sup>1</sup> A request unit is defined as 4 KB of data read or written. A request that writes or reads more than 4 KB will consume multiple units, for example, a 9 KB write will consume 3 write request units.
123+
<sup>1</sup> A request unit is defined as 4 KB of data read or written. A
124+
request that writes or reads more than 4 KB will consume multiple units, for
125+
example, a 9 KB write will consume 3 write request units.
87126

88-
<sup>2</sup> List operations are billed by read request units, based on the amount of data examined. For example, a list request that returns a combined 80 KB of keys and values will be billed 20 read request units. A list request that does not return anything is billed for 1 read request unit.
127+
<sup>2</sup> List operations are billed by read request units, based on the
128+
amount of data examined. For example, a list request that returns a combined 80
129+
KB of keys and values will be billed 20 read request units. A list request that
130+
does not return anything is billed for 1 read request unit.
89131

90132
<sup>3</sup> Each `setAlarm` is billed as a single write request unit.
91133

92-
<sup>4</sup> Delete requests are unmetered. For example, deleting a 100 KB value will be charged one delete request.
134+
<sup>4</sup> Delete requests are unmetered. For example, deleting a 100 KB value
135+
will be charged one delete request.
93136

94-
<sup>5</sup> Durable Objects will be billed for stored data until the data is removed. Once the data is removed, the object will be cleaned up automatically by the system.
137+
<sup>5</sup> Durable Objects will be billed for stored data until the data is
138+
removed. Once the data is removed, the object will be cleaned up automatically
139+
by the system.
95140

96141
Requests that hit the [Durable Objects in-memory cache](/durable-objects/reference/in-memory-state/) or that use the [multi-key versions of `get()`/`put()`/`delete()` methods](/durable-objects/api/storage-api/) are billed the same as if they were a normal, individual request for each key.
97142

0 commit comments

Comments
 (0)