-
Notifications
You must be signed in to change notification settings - Fork 10k
[DO] Reference DO name using init
#20309
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 16 commits
Commits
Show all changes
19 commits
Select commit
Hold shift + click to select a range
e5b7a95
Merge commit '3dea049f67246f2d1fe1748dab4e40284cb1731a' into jun/do/i…
Oxyjun d8bb9b3
Adding placeholder file
Oxyjun 8413bfa
Merge commit '3bd7c03c761d841684c6135103335750b6ab28f2' into jun/do/i…
Oxyjun 758c810
Setting up file for main code example.
Oxyjun 626846b
Adding new example chapter.
Oxyjun 884dab4
Adding temporary code snippet for workaround.
Oxyjun 4e66eb9
Fixing code block language
Oxyjun aa1f110
Update src/content/docs/durable-objects/examples/reference-do-name-us…
Oxyjun 12d91d9
update the code example
harshil1712 8f9a85c
Quick review + removing TypeScriptExample to avoid
Oxyjun a7206a0
Fixing linebreaks
Oxyjun 167cff9
remove example for D1
harshil1712 75f25c6
Shortening title
Oxyjun 99beb00
Merge branch 'jun/do/idFromName-example' of github.com:cloudflare/clo…
Oxyjun ba418b1
minor updates
harshil1712 5e8f2f8
Merge branch 'jun/do/idFromName-example' of github.com:cloudflare/clo…
harshil1712 c5b22d2
PCX review
Oxyjun cc3db5e
Apply suggestions from code review
Oxyjun e1fe994
Adding minor fix to trigger GH pipeline.
Oxyjun File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
268 changes: 268 additions & 0 deletions
268
src/content/docs/durable-objects/examples/reference-do-name-using-init.mdx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,268 @@ | ||
| --- | ||
| type: example | ||
| summary: Access the name from within a Durable Object using RpcTarget. | ||
| tags: | ||
| - Durable Objects | ||
| pcx_content_type: example | ||
| title: Use RpcTarget class to handle Durable Object metadata | ||
| sidebar: | ||
| order: 3 | ||
| description: Access the name from within a Durable Object using RpcTarget. | ||
| --- | ||
|
|
||
| import { TabItem, Tabs, GlossaryTooltip } from "~/components"; | ||
|
|
||
| When working with Durable Objects, you'll might need to access the name that was used to create the Durable Object via `idFromName()`. This name is typically a meaningful identifier that represents what the Durable Object is responsible for (like a user ID, room name, or resource identifier). | ||
|
|
||
| However, there's a limitation in the current implementation: even though you create a Durable Object with `.idFromName(name)`, you cannot directly access this name inside the Durable Object via `this.ctx.id.name`. | ||
Oxyjun marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| The `RpcTarget` pattern shown below offers a solution by creating a communication layer that automatically carries the name with each method call. This keeps your API clean while ensuring the Durable Object has access to its own name. | ||
|
|
||
| Based on your needs, you can either store the metadata temporarily in the `RpcTarget` class, or use Durable Object storage to persist the metadata for the lifetime of the object. | ||
|
|
||
| This example does not persist the Durable Object metadata. It demonstrates how to: | ||
|
|
||
| 1. Create an `RpcTarget` class | ||
| 2. Set the Durable Object metadata (identifier in this example) in the `RpcTarget` class | ||
| 3. Pass the metadata to a Durable Object method | ||
| 4. Clean up the `RpcTarget` class after use | ||
|
|
||
| ```ts | ||
| import { DurableObject, RpcTarget } from "cloudflare:workers"; | ||
|
|
||
| // * Create an RpcDO class that extends RpcTarget | ||
| // * Use this class to set the Durable Object metadata | ||
| // * Pass the metadata in the Durable Object methods | ||
| // * @param mainDo - The main Durable Object class | ||
| // * @param doIdentifier - The identifier of the Durable Object | ||
|
|
||
| export class RpcDO extends RpcTarget { | ||
| constructor( | ||
| private mainDo: MyDurableObject, | ||
| private doIdentifier: string, | ||
| ) { | ||
| super(); | ||
| } | ||
|
|
||
| // * Pass the user's name to the Durable Object method | ||
| // * @param userName - The user's name to pass to the Durable Object method | ||
|
|
||
| async computeMessage(userName: string): Promise<string> { | ||
| // Call the Durable Object method and pass the user's name and the Durable Object identifier | ||
| return this.mainDo.computeMessage(userName, this.doIdentifier); | ||
| } | ||
|
|
||
| // * Call the Durable Object method without using the Durable Object identifier | ||
| // * @param userName - The user's name to pass to the Durable Object method | ||
|
|
||
| async simpleGreeting(userName: string) { | ||
| return this.mainDo.simpleGreeting(userName); | ||
| } | ||
| } | ||
|
|
||
| // * Create a Durable Object class | ||
| // * You can use the RpcDO class to set the Durable Object metadata | ||
|
|
||
| export class MyDurableObject extends DurableObject<Env> { | ||
| constructor(ctx: DurableObjectState, env: Env) { | ||
| super(ctx, env); | ||
| } | ||
|
|
||
| // * Initialize the RpcDO class | ||
| // * You can set the Durable Object metadata here | ||
| // * It returns an instance of the RpcDO class | ||
| // * @param doIdentifier - The identifier of the Durable Object | ||
|
|
||
| async setMetaData(doIdentifier: string) { | ||
| return new RpcDO(this, doIdentifier); | ||
| } | ||
|
|
||
| // * Function that computes a greeting message using the user's name and DO identifier | ||
| // * @param userName - The user's name to include in the greeting | ||
| // * @param doIdentifier - The identifier of the Durable Object | ||
|
|
||
| async computeMessage( | ||
| userName: string, | ||
| doIdentifier: string, | ||
| ): Promise<string> { | ||
| console.log({ | ||
| userName: userName, | ||
| durableObjectIdentifier: doIdentifier, | ||
| }); | ||
| return `Hello, ${userName}! The identifier of this DO is ${doIdentifier}`; | ||
| } | ||
|
|
||
| // * Function that is not in the RpcTarget | ||
| // * Not every function has to be in the RpcTarget | ||
|
|
||
| private async notInRpcTarget() { | ||
| return "This is not in the RpcTarget"; | ||
| } | ||
|
|
||
| // * Function that takes the user's name and doesn't use the Durable Object identifier | ||
Oxyjun marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| // * @param userName - The user's name to include in the greeting | ||
|
|
||
| async simpleGreeting(userName: string) { | ||
| // Call the private function that is not in the RpcTarget | ||
| console.log(this.notInRpcTarget()); | ||
|
|
||
| return `Hello, ${userName}! This doesn't use the DO identifier.`; | ||
| } | ||
| } | ||
|
|
||
| export default { | ||
| async fetch(request, env, ctx): Promise<Response> { | ||
| let id: DurableObjectId = env.MY_DURABLE_OBJECT.idFromName( | ||
| new URL(request.url).pathname, | ||
| ); | ||
| let stub = env.MY_DURABLE_OBJECT.get(id); | ||
|
|
||
| // * Set the Durable Object metadata using the RpcTarget | ||
| // * Notice that no await is needed here | ||
|
|
||
| const rpcTarget = stub.setMetaData(id.name ?? "default"); | ||
|
|
||
| // Call the Durable Object method using the RpcTarget. | ||
| // The DO identifier is passed in the RpcTarget | ||
| const greeting = await rpcTarget.computeMessage("world"); | ||
|
|
||
| // Call the Durable Object method that doesn't use the Durable Object identifier | ||
Oxyjun marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| const simpleGreeting = await rpcTarget.simpleGreeting("world"); | ||
|
|
||
| // Clean up the RpcTarget. | ||
| try { | ||
| (await rpcTarget)[Symbol.dispose]?.(); | ||
| console.log("RpcTarget cleaned up."); | ||
| } catch (e) { | ||
| console.error({ | ||
| message: "RpcTarget could not be cleaned up.", | ||
| error: String(e), | ||
| errorProperties: e, | ||
| }); | ||
| } | ||
|
|
||
| return new Response(greeting, { status: 200 }); | ||
| }, | ||
| } satisfies ExportedHandler<Env>; | ||
| ``` | ||
|
|
||
| This example persists the Durable Object metadata. It demonstrates similar steps as the previous example, but uses Durable Object storage to store the identifier, eliminating the need to pass it through the RpcTarget. | ||
|
|
||
| ```ts | ||
| import { DurableObject, RpcTarget } from "cloudflare:workers"; | ||
|
|
||
| // * Create an RpcDO class that extends RpcTarget | ||
| // * Use this class to set the Durable Object metadata | ||
| // * Pass the metadata in the Durable Object methods | ||
| // * @param mainDo - The main Durable Object class | ||
| // * @param doIdentifier - The identifier of the Durable Object | ||
|
|
||
| export class RpcDO extends RpcTarget { | ||
| constructor( | ||
| private mainDo: MyDurableObject, | ||
| private doIdentifier: string, | ||
| ) { | ||
| super(); | ||
| } | ||
|
|
||
| // * Pass the user's name to the Durable Object method | ||
| // * @param userName - The user's name to pass to the Durable Object method | ||
|
|
||
| async computeMessage(userName: string): Promise<string> { | ||
| // Call the Durable Object method and pass the user's name and the Durable Object identifier | ||
| return this.mainDo.computeMessage(userName, this.doIdentifier); | ||
| } | ||
|
|
||
| // * Call the Durable Object method without using the Durable Object identifier | ||
| // * @param userName - The user's name to pass to the Durable Object method | ||
|
|
||
| async simpleGreeting(userName: string) { | ||
| return this.mainDo.simpleGreeting(userName); | ||
| } | ||
| } | ||
|
|
||
| // * Create a Durable Object class | ||
| // * You can use the RpcDO class to set the Durable Object metadata | ||
|
|
||
| export class MyDurableObject extends DurableObject<Env> { | ||
| constructor(ctx: DurableObjectState, env: Env) { | ||
| super(ctx, env); | ||
| } | ||
|
|
||
| // * Initialize the RpcDO class | ||
| // * You can set the Durable Object metadata here | ||
| // * It returns an instance of the RpcDO class | ||
| // * @param doIdentifier - The identifier of the Durable Object | ||
|
|
||
| async setMetaData(doIdentifier: string) { | ||
| // Use DO storage to store the Durable Object identifier | ||
| await this.ctx.storage.put("doIdentifier", doIdentifier); | ||
| return new RpcDO(this, doIdentifier); | ||
| } | ||
|
|
||
| // * Function that computes a greeting message using the user's name and DO identifier | ||
| // * @param userName - The user's name to include in the greeting | ||
|
|
||
| async computeMessage(userName: string): Promise<string> { | ||
| // Get the DO identifier from storage | ||
| const doIdentifier = await this.ctx.storage.get("doIdentifier"); | ||
| console.log({ | ||
| userName: userName, | ||
| durableObjectIdentifier: doIdentifier, | ||
| }); | ||
| return `Hello, ${userName}! The identifier of this DO is ${doIdentifier}`; | ||
| } | ||
|
|
||
| // * Function that is not in the RpcTarget | ||
| // * Not every function has to be in the RpcTarget | ||
|
|
||
| private async notInRpcTarget() { | ||
| return "This is not in the RpcTarget"; | ||
| } | ||
|
|
||
| // * Function that takes the user's name and doesn't use the Durable Object identifier | ||
Oxyjun marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| // * @param userName - The user's name to include in the greeting | ||
|
|
||
| async simpleGreeting(userName: string) { | ||
| // Call the private function that is not in the RpcTarget | ||
| console.log(this.notInRpcTarget()); | ||
|
|
||
| return `Hello, ${userName}! This doesn't use the DO identifier.`; | ||
| } | ||
| } | ||
|
|
||
| export default { | ||
| async fetch(request, env, ctx): Promise<Response> { | ||
| let id: DurableObjectId = env.MY_DURABLE_OBJECT.idFromName( | ||
| new URL(request.url).pathname, | ||
| ); | ||
| let stub = env.MY_DURABLE_OBJECT.get(id); | ||
|
|
||
| // * Set the Durable Object metadata using the RpcTarget | ||
| // * Notice that no await is needed here | ||
|
|
||
| const rpcTarget = stub.setMetaData(id.name ?? "default"); | ||
|
|
||
| // Call the Durable Object method using the RpcTarget. | ||
| // The DO identifier is stored in the Durable Object's storage | ||
| const greeting = await rpcTarget.computeMessage("world"); | ||
|
|
||
| // Call the Durable Object method that doesn't use the Durable Object identifier | ||
Oxyjun marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| const simpleGreeting = await rpcTarget.simpleGreeting("world"); | ||
|
|
||
| // Clean up the RpcTarget. | ||
| try { | ||
| (await rpcTarget)[Symbol.dispose]?.(); | ||
| console.log("RpcTarget cleaned up."); | ||
| } catch (e) { | ||
| console.error({ | ||
| message: "RpcTarget could not be cleaned up.", | ||
| error: String(e), | ||
| errorProperties: e, | ||
| }); | ||
| } | ||
|
|
||
| return new Response(greeting, { status: 200 }); | ||
| }, | ||
| } satisfies ExportedHandler<Env>; | ||
| ``` | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.