diff --git a/src/content/docs/durable-objects/api/alarms.mdx b/src/content/docs/durable-objects/api/alarms.mdx
index a6fcf26fe792c08..6d87fb19b7719b4 100644
--- a/src/content/docs/durable-objects/api/alarms.mdx
+++ b/src/content/docs/durable-objects/api/alarms.mdx
@@ -5,7 +5,7 @@ sidebar:
order: 8
---
-import { Type, GlossaryTooltip } from "~/components";
+import { Type, GlossaryTooltip, Tabs, TabItem } from "~/components";
## Background
@@ -84,6 +84,10 @@ This example shows how to both set alarms with the `setAlarm(timestamp)` method
- If an unexpected error terminates the Durable Object, the `alarm()` handler may be re-instantiated on another machine.
- Following a short delay, the `alarm()` handler will run from the beginning on the other machine.
+
+
+
+
```js
import { DurableObject } from "cloudflare:workers";
@@ -115,8 +119,47 @@ export class AlarmExample extends DurableObject {
}
```
+
+
+
+
+```python
+from workers import DurableObject, WorkerEntrypoint
+
+class Default(WorkerEntrypoint):
+ async def fetch(self, request):
+ return await self.env.ALARM_EXAMPLE.getByName("foo").fetch(request)
+
+SECONDS = 1000
+
+class AlarmExample(DurableObject):
+ def __init__(self, ctx, env):
+ super().__init__(ctx, env)
+ self.storage = ctx.storage
+
+ async def fetch(self, request):
+ # If there is no alarm currently set, set one for 10 seconds from now
+ current_alarm = await self.storage.getAlarm()
+ if current_alarm is None:
+ self.storage.setAlarm(Date.now() + 10 * SECONDS)
+
+ async def alarm(self):
+ # The alarm handler will be invoked whenever an alarm fires.
+ # You can use this to do work, read from the Storage API, make HTTP calls
+ # and set future alarms to run using self.storage.setAlarm() from within this handler.
+ pass
+```
+
+
+
+
+
The following example shows how to use the `alarmInfo` property to identify if the alarm event has been attempted before.
+
+
+
+
```js
class MyDurableObject extends DurableObject {
async alarm(alarmInfo) {
@@ -129,6 +172,21 @@ class MyDurableObject extends DurableObject {
}
```
+
+
+
+
+```python
+class MyDurableObject(DurableObject):
+ async def alarm(self, alarm_info):
+ if alarm_info and alarm_info.get('retryCount', 0) != 0:
+ print(f"This alarm event has been attempted {alarm_info.get('retryCount')} times before.")
+```
+
+
+
+
+
## Related resources
- Understand how to [use the Alarms API](/durable-objects/examples/alarms-api/) in an end-to-end example.
diff --git a/src/content/docs/durable-objects/api/base.mdx b/src/content/docs/durable-objects/api/base.mdx
index 06e5311807d623a..c741c4f3b9417e2 100644
--- a/src/content/docs/durable-objects/api/base.mdx
+++ b/src/content/docs/durable-objects/api/base.mdx
@@ -9,7 +9,9 @@ import { Render, Tabs, TabItem, GlossaryTooltip, Type, MetaInfo, TypeScriptExamp
The `DurableObject` base class is an abstract class which all Durable Objects inherit from. This base class provides a set of optional methods, frequently referred to as handler methods, which can respond to events, for example a webSocketMessage when using the [WebSocket Hibernation API](/durable-objects/best-practices/websockets/#websocket-hibernation-api). To provide a concrete example, here is a Durable Object `MyDurableObject` which extends `DurableObject` and implements the fetch handler to return "Hello, World!" to the calling Worker.
-
+
+
+
```ts
export class MyDurableObject extends DurableObject {
constructor(ctx: DurableObjectState, env: Env) {
@@ -23,6 +25,23 @@ export class MyDurableObject extends DurableObject {
```
+
+
+```python
+from workers import DurableObject, Response
+
+class MyDurableObject(DurableObject):
+ def __init__(self, ctx, env):
+ super().__init__(ctx, env)
+
+ async def fetch(self, request):
+ return Response("Hello, World!")
+```
+
+
+
+
+
## Methods
### `fetch`
diff --git a/src/content/docs/durable-objects/api/container.mdx b/src/content/docs/durable-objects/api/container.mdx
index a4a7ba70dfa420a..cdc4276a974751f 100644
--- a/src/content/docs/durable-objects/api/container.mdx
+++ b/src/content/docs/durable-objects/api/container.mdx
@@ -25,7 +25,9 @@ It is likely preferable to use the official `Container` class, which provides he
a more idiomatic API for working with containers on top of Durable Objects.
:::
-
+
+
+
```ts
export class MyDurableObject extends DurableObject {
constructor(ctx: DurableObjectState, env: Env) {
@@ -42,6 +44,25 @@ export class MyDurableObject extends DurableObject {
```
+
+
+```python
+from workers import DurableObject
+
+class MyDurableObject(DurableObject):
+ def __init__(self, ctx, env):
+ super().__init__(ctx, env)
+
+ # boot the container when starting the DO
+ async def start_container():
+ self.ctx.container.start()
+ self.ctx.blockConcurrencyWhile(start_container)
+```
+
+
+
+
+
## Attributes
@@ -49,10 +70,26 @@ export class MyDurableObject extends DurableObject {
`running` returns `true` if the container is currently running. It does not ensure that the container has fully started and ready to accept requests.
+
+
+
+
```js
- this.ctx.container.running;
+this.ctx.container.running;
+```
+
+
+
+
+
+```python
+self.ctx.container.running
```
+
+
+
+
## Methods
### `start`
@@ -60,6 +97,10 @@ export class MyDurableObject extends DurableObject {
`start` boots a container. This method does not block until the container is fully started.
You may want to confirm the container is ready to accept requests before using it.
+
+
+
+
```js
this.ctx.container.start({
env: {
@@ -70,6 +111,26 @@ this.ctx.container.start({
});
```
+
+
+
+
+```python
+from pyodide.ffi import to_js
+
+self.ctx.container.start(
+ env = to_js({
+ "FOO": "bar",
+ }),
+ enableInternet = False,
+ entrypoint = to_js(["node", "server.js"]),
+)
+```
+
+
+
+
+
#### Parameters
- `options` (optional): An object with the following properties:
@@ -85,10 +146,26 @@ this.ctx.container.start({
`destroy` stops the container and optionally returns a custom error message to the `monitor()` error callback.
+
+
+
+
```js
this.ctx.container.destroy("Manually Destroyed");
```
+
+
+
+
+```python
+self.ctx.container.destroy("Manually Destroyed")
+```
+
+
+
+
+
#### Parameters
- `error` (optional): A string that will be sent to the error handler of the `monitor` method. This is useful for logging or debugging purposes.
@@ -101,11 +178,28 @@ this.ctx.container.destroy("Manually Destroyed");
`signal` sends an IPC signal to the container, such as SIGKILL or SIGTERM. This is useful for stopping the container gracefully or forcefully.
+
+
+
+
```js
const SIGTERM = 15;
this.ctx.container.signal(SIGTERM);
```
+
+
+
+
+```python
+SIGTERM = 15
+self.ctx.container.signal(SIGTERM)
+```
+
+
+
+
+
#### Parameters
- `signal`: a number representing the signal to send to the container. This is typically a POSIX signal number, such as SIGTERM (15) or SIGKILL (9).
@@ -118,6 +212,10 @@ this.ctx.container.signal(SIGTERM);
`getTcpPort` returns a TCP port from the container. This can be used to communicate with the container over TCP and HTTP.
+
+
+
+
```js
const port = this.ctx.container.getTcpPort(8080);
const res = await port.fetch("http://container/set-state", {
@@ -141,6 +239,38 @@ try {
}
```
+
+
+
+
+```python
+port = self.ctx.container.getTcpPort(8080)
+res = await port.fetch(
+ "http://container/set-state",
+ body = initial_state,
+ method = "POST",
+)
+```
+
+```python
+from workers import Response
+
+conn = self.ctx.container.getTcpPort(8080).connect('10.0.0.1:8080')
+await conn.opened
+
+try:
+ if request.body:
+ await request.body.pipeTo(conn.writable)
+ return Response(conn.readable)
+except Exception as err:
+ print(f"Request body piping failed: {err}")
+ return Response("Failed to proxy request body", status=502)
+```
+
+
+
+
+
#### Parameters
- `port` (number): a TCP port number to use for communication with the container.
@@ -154,6 +284,10 @@ try {
`monitor` returns a promise that resolves when a container exits and errors if a container errors. This is useful for setting up
callbacks to handle container status changes in your Workers code.
+
+
+
+
```js
class MyContainer extends DurableObject {
constructor(ctx, env) {
@@ -173,6 +307,32 @@ class MyContainer extends DurableObject {
}
```
+
+
+
+
+```python
+from workers import DurableObject
+
+class MyContainer(DurableObject):
+ def __init__(self, ctx, env):
+ super().__init__(ctx, env)
+
+ def on_container_exit():
+ print("Container exited")
+
+ # the "err" value can be customized by the destroy() method
+ async def on_container_error(err):
+ print(f"Container errored: {err}")
+
+ self.ctx.container.start()
+ self.ctx.container.monitor().then(on_container_exit).catch(on_container_error)
+```
+
+
+
+
+
#### Parameters
- None
diff --git a/src/content/docs/durable-objects/api/id.mdx b/src/content/docs/durable-objects/api/id.mdx
index c092059522df973..c230619e82724fb 100644
--- a/src/content/docs/durable-objects/api/id.mdx
+++ b/src/content/docs/durable-objects/api/id.mdx
@@ -39,12 +39,30 @@ If you are experiencing an issue with a particular Durable Object, you may wish
`equals` is used to compare equality between two instances of `DurableObjectId`.
+
+
+
+
```js
const id1 = env.MY_DURABLE_OBJECT.newUniqueId();
const id2 = env.MY_DURABLE_OBJECT.newUniqueId();
console.assert(!id1.equals(id2), "Different unique ids should never be equal.");
```
+
+
+
+
+```python
+id1 = env.MY_DURABLE_OBJECT.newUniqueId()
+id2 = env.MY_DURABLE_OBJECT.newUniqueId()
+assert not id1.equals(id2), "Different unique ids should never be equal."
+```
+
+
+
+
+
#### Parameters
- A required `DurableObjectId` to compare against.
@@ -59,6 +77,10 @@ console.assert(!id1.equals(id2), "Different unique ids should never be equal.");
`name` is an optional property of a `DurableObjectId`, which returns the name that was used to create the `DurableObjectId` via [`DurableObjectNamespace::idFromName`](/durable-objects/api/namespace/#idfromname). This value is undefined if the `DurableObjectId` was constructed using [`DurableObjectNamespace::newUniqueId`](/durable-objects/api/namespace/#newuniqueid). This value is also undefined within the `ctx.id` passed into the Durable Object constructor (refer to [GitHub issue](https://github.com/cloudflare/workerd/issues/2240) for discussion).
+
+
+
+
```js
const uniqueId = env.MY_DURABLE_OBJECT.newUniqueId();
const fromNameId = env.MY_DURABLE_OBJECT.idFromName("foo");
@@ -69,6 +91,21 @@ console.assert(
);
```
+
+
+
+
+```python
+unique_id = env.MY_DURABLE_OBJECT.newUniqueId()
+from_name_id = env.MY_DURABLE_OBJECT.idFromName("foo")
+assert unique_id.name is None, "unique ids have no name"
+assert from_name_id.name == "foo", "name matches parameter to idFromName"
+```
+
+
+
+
+
## Related resources
- [Durable Objects: Easy, Fast, Correct – Choose Three](https://blog.cloudflare.com/durable-objects-easy-fast-correct-choose-three/).
diff --git a/src/content/docs/durable-objects/api/legacy-kv-storage-api.mdx b/src/content/docs/durable-objects/api/legacy-kv-storage-api.mdx
index dc65312e32b12d9..116f39c4403d0d7 100644
--- a/src/content/docs/durable-objects/api/legacy-kv-storage-api.mdx
+++ b/src/content/docs/durable-objects/api/legacy-kv-storage-api.mdx
@@ -5,7 +5,7 @@ sidebar:
order: 7
---
-import { Render, Type, MetaInfo, GlossaryTooltip, TypeScriptExample, Details } from "~/components";
+import { Render, Type, MetaInfo, GlossaryTooltip, TypeScriptExample, Details, Tabs, TabItem } from "~/components";
:::note
This page documents the storage API for legacy KV-backed Durable Objects.
@@ -23,7 +23,9 @@ Durable Objects gain access to Storage API via the `DurableObjectStorage` interf
The following code snippet shows you how to store and retrieve data using the Durable Object Storage API.
-
+
+
+
```ts
export class Counter extends DurableObject {
constructor(ctx: DurableObjectState, env: Env) {
@@ -40,6 +42,26 @@ export class Counter extends DurableObject {
```
+
+
+```python
+from workers import DurableObject
+
+class Counter(DurableObject):
+ def __init__(self, ctx, env):
+ super().__init__(ctx, env)
+
+ async def increment(self):
+ value = (await self.ctx.storage.get("value")) or 0
+ value += 1
+ await self.ctx.storage.put("value", value)
+ return value
+```
+
+
+
+
+
JavaScript is a single-threaded and event-driven programming language. This means that JavaScript runtimes, by default, allow requests to interleave with each other which can lead to concurrency bugs. The Durable Objects runtime uses a combination of input gates and output gates to avoid this type of concurrency bug when performing storage operations. Learn more in our [blog post](https://blog.cloudflare.com/durable-objects-easy-fast-correct-choose-three/).
## Asynchronous KV API
diff --git a/src/content/docs/durable-objects/api/namespace.mdx b/src/content/docs/durable-objects/api/namespace.mdx
index 7ab73345e309836..a1bfe0aec9d291f 100644
--- a/src/content/docs/durable-objects/api/namespace.mdx
+++ b/src/content/docs/durable-objects/api/namespace.mdx
@@ -59,7 +59,28 @@ export default {
} satisfies ExportedHandler;
```
-
+
+
+
+
+```python
+from workers import DurableObject, WorkerEntrypoint
+
+# Durable Object
+class MyDurableObject(DurableObject):
+ pass
+
+# Worker
+class Default(WorkerEntrypoint):
+ async def fetch(self, request):
+ # A stub is a client Object used to invoke methods defined by the Durable Object
+ stub = self.env.MY_DURABLE_OBJECT.getByName("foo")
+ # ...
+```
+
+
+
+
## Methods
diff --git a/src/content/docs/durable-objects/api/sqlite-storage-api.mdx b/src/content/docs/durable-objects/api/sqlite-storage-api.mdx
index 409b2270a8d3ac0..61cae6321b32d83 100644
--- a/src/content/docs/durable-objects/api/sqlite-storage-api.mdx
+++ b/src/content/docs/durable-objects/api/sqlite-storage-api.mdx
@@ -5,7 +5,7 @@ sidebar:
order: 6
---
-import { Render, Type, MetaInfo, GlossaryTooltip, TypeScriptExample, Details } from "~/components";
+import { Render, Type, MetaInfo, GlossaryTooltip, TypeScriptExample, Details, Tabs, TabItem } from "~/components";
:::note
This page documents the storage API for the newer SQLite-backed Durable Objects.
@@ -25,7 +25,9 @@ Durable Objects gain access to Storage API via the `DurableObjectStorage` interf
The following code snippet shows you how to store and retrieve data using the Durable Object Storage API.
-
+
+
+
```ts
export class Counter extends DurableObject {
constructor(ctx: DurableObjectState, env: Env) {
@@ -44,6 +46,26 @@ export class Counter extends DurableObject {
```
+
+
+```python
+from workers import DurableObject
+
+class Counter(DurableObject):
+ def __init__(self, ctx, env):
+ super().__init__(ctx, env)
+
+ async def increment(self):
+ value = (await self.ctx.storage.get('value')) or 0
+ value += 1
+ await self.ctx.storage.put('value', value)
+ return value
+```
+
+
+
+
+
JavaScript is a single-threaded and event-driven programming language. This means that JavaScript runtimes, by default, allow requests to interleave with each other which can lead to concurrency bugs. The Durable Objects runtime uses a combination of input gates and output gates to avoid this type of concurrency bug when performing storage operations. Learn more in our [blog post](https://blog.cloudflare.com/durable-objects-easy-fast-correct-choose-three/).
## SQL API
@@ -52,6 +74,10 @@ The `SqlStorage` interface encapsulates methods that modify the SQLite database
For example, using `sql.exec()` a user can create a table and insert rows.
+
+
+
+
```ts
import { DurableObject } from "cloudflare:workers";
@@ -75,6 +101,34 @@ export class MyDurableObject extends DurableObject {
}
```
+
+
+
+
+```python
+from workers import DurableObject
+
+class MyDurableObject(DurableObject):
+ def __init__(self, ctx, env):
+ super().__init__(ctx, env)
+ self.sql = ctx.storage.sql
+
+ self.sql.exec("""
+ CREATE TABLE IF NOT EXISTS artist(
+ artistid INTEGER PRIMARY KEY,
+ artistname TEXT
+ );
+ INSERT INTO artist (artistid, artistname) VALUES
+ (123, 'Alice'),
+ (456, 'Bob'),
+ (789, 'Charlie');
+ """)
+```
+
+
+
+
+
- SQL API methods accessed with `ctx.storage.sql` are only allowed on [Durable Object classes with SQLite storage backend](/durable-objects/best-practices/access-durable-objects-storage/#create-sqlite-backed-durable-object-class) and will return an error if called on Durable Object classes with a KV-storage backend.
- When writing data, every row update of an index counts as an additional row. However, indexes may be beneficial for read-heavy use cases. Refer to [Index for SQLite Durable Objects](/durable-objects/best-practices/access-durable-objects-storage/#index-for-sqlite-durable-objects).
- Writing data to [SQLite virtual tables](https://www.sqlite.org/vtab.html) also counts towards rows written.
@@ -109,6 +163,10 @@ A cursor (`SqlStorageCursor`) to iterate over query row results as objects. `Sql
- Returned Iterator supports `next()` and `toArray()` methods above.
- Returned cursor and `raw()` iterator iterate over the same query results and can be combined. For example:
+
+
+
+
```ts
let cursor = this.sql.exec("SELECT * FROM artist ORDER BY artistname ASC;");
let rawResult = cursor.raw().next();
@@ -122,6 +180,27 @@ if (!rawResult.done) {
console.log(cursor.toArray()); // prints [{ artistid: 456, artistname: 'Bob' },{ artistid: 789, artistname: 'Charlie' }]
```
+
+
+
+
+```python
+cursor = self.sql.exec("SELECT * FROM artist ORDER BY artistname ASC;")
+raw_result = cursor.raw().next()
+
+if not raw_result.done:
+ print(raw_result.value) # prints [ 123, 'Alice' ]
+else:
+ # query returned zero results
+ pass
+
+print(cursor.toArray()) # prints [{ artistid: 456, artistname: 'Bob' },{ artistid: 789, artistname: 'Charlie' }]
+```
+
+
+
+
+
`SqlStorageCursor` has the following properties:
- `columnNames`:
@@ -148,10 +227,26 @@ Note that `sql.exec()` cannot execute transaction-related statements like `BEGIN
The current SQLite database size in bytes.
+
+
+
+
```ts
let size = ctx.storage.sql.databaseSize;
```
+
+
+
+
+```python
+size = ctx.storage.sql.databaseSize
+```
+
+
+
+
+
## PITR (Point In Time Recovery) API
For [SQLite-backed Durable Objects](/durable-objects/best-practices/access-durable-objects-storage/#create-sqlite-backed-durable-object-class), the following point-in-time-recovery (PITR) API methods are available to restore a Durable Object's embedded SQLite database to any point in time in the past 30 days. These methods apply to the entire SQLite database contents, including both the object's stored SQL data and stored key-value data using the key-value `put()` API. The PITR API is not supported in local development because a durable log of data changes is not stored locally.
@@ -178,6 +273,10 @@ The PITR API represents points in time using 'bookmarks'. A bookmark is a mostly
This method returns a special bookmark representing the point in time immediately before the recovery takes place (even though that point in time is still technically in the future). Thus, after the recovery completes, it can be undone by performing a second recovery to this bookmark.
+
+
+
+
```ts
let now = new Date();
// restore to 2 days ago
@@ -185,6 +284,23 @@ let bookmark = ctx.storage.getBookmarkForTime(now - 2);
ctx.storage.onNextSessionRestoreBookmark(bookmark);
```
+
+
+
+
+```python
+from datetime import datetime, timedelta
+
+now = datetime.now()
+# restore to 2 days ago
+bookmark = ctx.storage.getBookmarkForTime(now - timedelta(days=2))
+ctx.storage.onNextSessionRestoreBookmark(bookmark)
+```
+
+
+
+
+
## Synchronous KV API
diff --git a/src/content/docs/durable-objects/api/state.mdx b/src/content/docs/durable-objects/api/state.mdx
index 858d04b764cb38f..5129d5186cfcf40 100644
--- a/src/content/docs/durable-objects/api/state.mdx
+++ b/src/content/docs/durable-objects/api/state.mdx
@@ -47,7 +47,24 @@ export class MyDurableObject extends DurableObject {
}
```
-
+
+
+
+
+```python
+from workers import DurableObject
+
+# Durable Object
+class MyDurableObject(DurableObject):
+ # DurableObjectState is accessible via the ctx instance property
+ def __init__(self, ctx, env):
+ super().__init__(ctx, env)
+ # ...
+```
+
+
+
+
## Methods and Properties
@@ -93,6 +110,10 @@ In practice, this is quite rare, and most use cases do not need `blockConcurrenc
:::
+
+
+
+
```js
// Durable Object
export class MyDurableObject extends DurableObject {
@@ -110,6 +131,28 @@ export class MyDurableObject extends DurableObject {
}
```
+
+
+
+
+```python
+# Durable Object
+class MyDurableObject(DurableObject):
+ def __init__(self, ctx, env):
+ super().__init__(ctx, env)
+ self.initialized = False
+
+ # blockConcurrencyWhile will ensure that initialized will always be true
+ async def set_initialized():
+ self.initialized = True
+ self.ctx.blockConcurrencyWhile(set_initialized)
+ # ...
+```
+
+
+
+
+
#### Parameters
- A required callback which returns a `Promise`.
@@ -253,6 +296,10 @@ If no parameter or a parameter of `0` is provided and a timeout has been previou
`abort` is used to forcibly reset a Durable Object. A JavaScript `Error` with the message passed as a parameter will be logged. This error is not able to be caught within the application code.
+
+
+
+
```js
// Durable Object
export class MyDurableObject extends DurableObject {
@@ -267,6 +314,25 @@ export class MyDurableObject extends DurableObject {
}
```
+
+
+
+
+```python
+# Durable Object
+class MyDurableObject(DurableObject):
+ def __init__(self, ctx, env):
+ super().__init__(ctx, env)
+
+ async def say_hello(self):
+ # Error: Hello, World! will be logged
+ self.ctx.abort("Hello, World!")
+```
+
+
+
+
+
:::caution[Not available in local development]
`abort` is not available in local development with the `wrangler dev` CLI command.
diff --git a/src/content/docs/durable-objects/api/stub.mdx b/src/content/docs/durable-objects/api/stub.mdx
index 227e622105199bf..452e8655cdc9396 100644
--- a/src/content/docs/durable-objects/api/stub.mdx
+++ b/src/content/docs/durable-objects/api/stub.mdx
@@ -5,7 +5,7 @@ sidebar:
order: 4
---
-import { Render, GlossaryTooltip } from "~/components";
+import { Render, GlossaryTooltip, Tabs, TabItem } from "~/components";
## Description
@@ -23,21 +23,56 @@ If an exception is thrown by a Durable Object stub<
`id` is a property of the `DurableObjectStub` corresponding to the [`DurableObjectId`](/durable-objects/api/id) used to create the stub.
+
+
+
+
```js
const id = env.MY_DURABLE_OBJECT.newUniqueId();
const stub = env.MY_DURABLE_OBJECT.get(id);
console.assert(id.equals(stub.id), "This should always be true");
```
+
+
+
+
+```python
+id = env.MY_DURABLE_OBJECT.newUniqueId()
+stub = env.MY_DURABLE_OBJECT.get(id)
+assert id.equals(stub.id), "This should always be true"
+```
+
+
+
+
+
### `name`
`name` is an optional property of a `DurableObjectStub`, which returns a name if it was provided upon stub creation either directly via [`DurableObjectNamespace::getByName`](/durable-objects/api/namespace/#getbyname) or indirectly via a [`DurableObjectId`](/durable-objects/api/id) created by [`DurableObjectNamespace::idFromName`](/durable-objects/api/namespace/#idfromname). This value is undefined if the [`DurableObjectId`](/durable-objects/api/id) used to create the `DurableObjectStub` was constructed using [`DurableObjectNamespace::newUniqueId`](/durable-objects/api/namespace/#newuniqueid).
+
+
+
+
```js
const stub = env.MY_DURABLE_OBJECT.getByName("foo");
console.assert(stub.name === "foo", "This should always be true");
```
+
+
+
+
+```python
+stub = env.MY_DURABLE_OBJECT.getByName("foo")
+assert stub.name == "foo", "This should always be true"
+```
+
+
+
+
+
## Related resources
- [Durable Objects: Easy, Fast, Correct – Choose Three](https://blog.cloudflare.com/durable-objects-easy-fast-correct-choose-three/).