new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

Cloudflare Workers · Runtime APIs · all subjects

service-bindings

41 notes, read out of this brain and free to use. Each one was extracted from a source and is re-checked against its exam.

WorkerEntrypoint class for RPC methods

To provide RPC methods from your Worker, extend the built-in WorkerEntrypoint class. A new instance of the class is created every time the Worker is called. The class instance is stateless and only lasts for the duration of the invocation. If you need to persist or coordinate state, use Durable Objects instead.

Service bindings RPC Worker-to-Worker communication

Service bindings allow one Worker to call into another without going through a publicly-accessible URL. You can use Service bindings to create internal APIs by extending WorkerEntrypoint and adding public methods. These public methods can be directly called by other Workers on your Cloudflare account that declare a binding to this Worker.

Accessing env object in WorkerEntrypoint

The env object is exposed as a class property of the WorkerEntrypoint class and contains all declared bindings, including environment variables, D1 databases, KV namespaces, and other binding types. Access bindings via this.env.BINDING_NAME.

Accessing ctx object in WorkerEntrypoint

The ctx object is exposed as a class property of the WorkerEntrypoint class. Use ctx.waitUntil() to extend the lifetime of the invocation context, allowing background tasks to continue running even after the method returns a value to the caller.

RPC communication with Durable Objects

You can use RPC to communicate between Workers and Durable Objects, in addition to Worker-to-Worker communication.

Fetching static assets from RPC methods

If your Worker has a static assets binding, call this.env.ASSETS.fetch() from within an RPC method. Since RPC methods do not receive a request parameter, construct a Request object with any hostname (the hostname is ignored by the assets binding; only the pathname matters). The convention is to use a hostname like assets.local for clarity.

Named entrypoints for multiple WorkerEntrypoint exports

You can export any number of named WorkerEntrypoint classes from within a single Worker, in addition to the default export. This allows you to group multiple pieces of compute together and declare Service bindings to specific named entrypoints. Configure this in wrangler.toml by specifying the entrypoint property in the services binding.

RPC method example with JavaScript WorkerEntrypoint

Example of a Worker implementing an add(a, b) method: import { WorkerEntrypoint } from "cloudflare:workers"; export default class extends WorkerEntrypoint { async add(a, b) { return a + b; } }

RPC method example with Python WorkerEntrypoint

Example of a Worker implementing an add(a, b) method: from workers import WorkerEntrypoint class Default(WorkerEntrypoint): async def add(self, a, b): return a + b

Accessing environment variables in WorkerEntrypoint JavaScript example

Example of accessing GREETING environment variable: import { WorkerEntrypoint } from "cloudflare:workers"; export default class extends WorkerEntrypoint { fetch() { return new Response("Hello from my-worker"); } async greet(name) { return this.env.GREETING + name; } }

Using ctx.waitUntil() in RPC method JavaScript example

Example of extending invocation context: import { WorkerEntrypoint } from "cloudflare:workers"; export default class extends WorkerEntrypoint { fetch() { return new Response("Hello from my-worker"); } async signup(email, name) { // sendEvent() will continue running, even after this method returns a value to the caller this.ctx.waitUntil(this.#sendEvent("signup", email)) // Perform any other work return "Success"; } async #sendEvent(eventName, email) { //... } }

Fetching static assets via RPC method JavaScript example

Example of fetching static assets: import { WorkerEntrypoint } from "cloudflare:workers"; export class ImageWorker extends WorkerEntrypoint { async getImage(path: string): Promise<Response> { return this.env.ASSETS.fetch( new Request(`https://assets.local${path}`) ); } } Caller invokes: const response = await env.IMAGE_SERVICE.getImage("/images/logo.png");

Named entrypoints with D1 database example

Example of multiple named entrypoints in a single Worker accessing D1: import { WorkerEntrypoint } from "cloudflare:workers"; export class AdminEntrypoint extends WorkerEntrypoint { async createUser(username) { await this.env.D1.prepare("INSERT INTO users (username) VALUES (?)") .bind(username) .run(); } async deleteUser(username) { await this.env.D1.prepare("DELETE FROM users WHERE username = ?") .bind(username) .run(); } } export class UserEntrypoint extends WorkerEntrypoint { async getTasks(userId) { return await this.env.D1.prepare( "SELECT title FROM tasks WHERE user_id = ?" ) .bind(userId) .run(); } async createTask(userId, title) { await this.env.D1.prepare( "INSERT INTO tasks (user_id, title) VALUES (?, ?)" ) .bind(userId, title) .run(); } } export default class extends WorkerEntrypoint { async fetch(request, env) { return new Response("Hello from my to do app"); } }

Service binding to named entrypoint configuration

To bind to a named entrypoint, configure wrangler.toml with the entrypoint property: { "name": "admin-app", "services": [ { "binding": "ADMIN", "service": "todo-app", "entrypoint": "AdminEntrypoint" } ] }

RPC call to named entrypoint example

Example of calling a named entrypoint via RPC: export default { async fetch(request, env) { await env.ADMIN.createUser("aNewUser"); return new Response("Hello from admin app"); }, };

RPC similar to local JavaScript function calls

The RPC system in Workers is designed to feel as similar as possible to calling a JavaScript function in the same Worker. In most cases, you should be able to write code the same way you would if everything was in a single Worker.

ctx.props for resource-specific bindings example

Example wrangler configuration showing props used for resource-specific bindings: { "services": [ { "binding": "FOO_DOCUMENT", "service": "doc-worker", "entrypoint": "DocumentApi", "props": { "docId": "e366592caec1d88dff724f74136b58b5", "permissions": [ "read", "write" ] } } ] } The DocumentApi class can be designed to provide an API to the specific document identified by ctx.props.docId, enforcing the given permissions.

ctx.props for passing configuration in service bindings

ctx.props provides a way to pass additional configuration to a worker based on the context in which it was invoked. When a Worker is called by another Worker through a Service Binding, ctx.props can provide information about the calling worker. The props value in the wrangler configuration is an arbitrary JSON value that the receiving WorkerEntrypoint instance can access as this.ctx.props. The Workers platform ensures that ctx.props can only be set by someone with permission to edit and deploy the worker, making the content authentic without need for secret keys or cryptographic signatures.

Specifying ctx.props dynamically in ctx.exports loopback bindings

Loopback Service Bindings in ctx.exports have a capability that regular Service Bindings do not: the caller can specify the value of ctx.props that should be delivered to the callee. This is done by calling the exported class as a function with an object containing a props property, like ctx.exports.ClassName({ props: { key: value } }). This is permitted because the caller is the same Worker and can be presumed to be trusted. Props values specified this way can contain any persistently serializable type, including structured clonable data types and Service Bindings themselves.

ctx.exports loopback binding example with custom props

Example demonstrating ctx.exports with custom props specification: import { WorkerEntrypoint } from 'cloudflare:workers'; export class Greeter extends WorkerEntrypoint { greet(name) { return `${this.ctx.props.greeting}, ${name}!`; } } export default { async fetch(request, env, ctx) { let greeter = ctx.exports.Greeter({ props: { greeting: 'Welcome' } }); let greeting = await greeter.greet('World'); return new Response(greeting); }, }; This creates a custom greeter that uses the greeting 'Welcome' and returns 'Welcome, World!'

ctx.props in Service Binding configuration example

Example wrangler configuration showing props in a Service Binding: { "services": [ { "binding": "DOC_SERVICE", "service": "doc-worker", "entrypoint": "DocServiceApi", "props": { "clientId": "frontend-worker", "permissions": [ "read", "write" ] } } ] } The receiving DocServiceApi instance can access this props value as this.ctx.props.

Manual stub creation with RpcStub constructor

You can manually create a stub locally using the RpcStub constructor from the cloudflare:workers module. This allows you to pass the same stub instance across RPC multiple times by creating a dup() for each time you send it. When passing a stub over RPC, ownership transfers to the recipient, so you must make a dup() for each recipient. When all duplicates are disposed, the original RpcTarget's disposer will be invoked.

Example: using declaration with RPC stub

```js function sendEmail(id, message) { using user = await env.USER_SERVICE.findUser(id); await user.sendEmail(message); // user[Symbol.dispose]() is implicitly called at the end of the scope. } ``` This example shows using the `using` declaration to ensure an RPC stub is disposed when the function scope ends.

Example: equivalent try-finally for using declaration

```js { const counter = await env.COUNTER_SERVICE.newCounter(); try { await counter.increment(2); await counter.increment(4); } finally { counter[Symbol.dispose](); } } ``` This shows what the `using` declaration is equivalent to. A `using` declaration automatically wraps the code in a try-finally block that calls Symbol.dispose().

Example: dup() method for stub duplication

```js let stub = await env.SOME_SERVICE.getThing(); // Create a duplicate. let stub2 = stub.dup(); // Call some function that will dispose the stub. await func(stub); // stub2 is still valid ``` This example shows using dup() to create a new handle to the same remote object when you need to pass a stub to a function that will dispose it while keeping another reference.

Example: manual RpcStub creation for multiple sends

```js import { RpcTarget, RpcStub } from "cloudflare:workers"; class Foo extends RpcTarget { // ... } let obj = new Foo(); let stub = new RpcStub(obj); await rpc1(stub.dup()); // sends a dup of `stub` await rpc2(stub.dup()); // sends another dup of `stub` stub[Symbol.dispose](); // disposes the original stub // obj's disposer will be called when the other two stubs // are disposed remotely. ``` This example shows creating a local stub manually and sending duplicates over RPC multiple times to avoid creating multiple independent stubs of the same RpcTarget instance.

RPC stubs require explicit disposal for memory management

When calling another Worker over RPC using a Service binding and the called method returns an object extending RpcTarget, the client receives a stub pointing to that remote object. As long as the stub exists on the client, the corresponding object on the server cannot be garbage collected. Each isolate has its own garbage collector that cannot see into other isolates, so the calling isolate must send an explicit signal to dispose the stub for the server's isolate to know the object can be collected.

Automatic stub disposal at end of event handler

The RPC system automatically disposes stubs when an event handler is done. For a fetch() handler, stubs created during event handling are automatically disposed when the final HTTP response is sent. The execution context begins when the handler is invoked and ends when the HTTP response is sent. The context can end early if the client disconnects, or be extended past its normal endpoint by calling ctx.waitUntil().

Automatic stub disposal for parameters in RPC calls

When stubs are received in the parameters of an RPC call, those stubs are automatically disposed when the call returns. If you wish to keep the stubs longer than that, you must call the dup() method on them.

RpcTarget disposer implementation

A class extending RpcTarget can optionally implement a disposer by declaring a Symbol.dispose method. The disposer runs after the last stub is disposed. The client-side call to the stub's disposer does not wait for the server-side disposer to be called; the server's disposer is called later. Exceptions thrown by the disposer do not propagate to the client but are reported as uncaught exceptions. RpcTarget's disposer must be declared as Symbol.dispose; Symbol.asyncDispose is not supported.

The dup() method for stub duplication

The dup() method creates a new handle pointing at the same RpcTarget instance, which must be independently disposed. This is useful when passing a stub to a function that will dispose the stub, but you also want to keep the stub for later use. If the RpcTarget class has a disposer, the disposer is only invoked when all duplicates have been disposed. Duplicates created from the same stub are considered related; if the same RpcTarget instance is passed over RPC multiple times separately, a new stub is created each time and these are not considered duplicates.

Disposing RPC object results disposes contained stubs

When an RPC returns any kind of object, that object will have a disposer added by the system. Disposing the object will dispose all stubs returned by the call. For example, if an RPC returns an array of four stubs, the array itself has a disposer that disposes all four stubs. Primitive values like numbers or strings do not have disposers because they cannot contain stubs. You should store RPC results in a using declaration to ensure any contained stubs are disposed.

WorkerEntrypoint RPC execution context behavior

A Worker invoked via RPC has an execution context that begins when an RPC method on a WorkerEntrypoint is invoked. If no stubs are passed in the parameters or results of the RPC, the context ends when the RPC returns. If any stubs are passed, the execution context is implicitly extended until all such stubs are disposed and all calls made through them have returned. If the client disconnects, the server's execution context is canceled immediately regardless of stub existence. A client that is another Worker is considered disconnected when its own execution context ends. The context can be extended with ctx.waitUntil().

fetch() method special semantics in WorkerEntrypoint and DurableObject

The fetch() method has special semantics when defined in a class extending WorkerEntrypoint or DurableObject. It can only be used to handle HTTP requests, equivalent to the fetch handler. The method must accept exactly one parameter of type Request and must return a Response or a Promise of a Response. On the client side, fetch() called on a service binding or Durable Object stub works like the standard global fetch(), where the caller may pass one or two parameters. If the caller does not pass a single Request object, a new Request is implicitly constructed with the passed parameters, and that request is sent to the server. Some Request properties like redirect: "auto" (the default) control client-side behavior and are not sent to the server; for example, redirect: "auto" instructs fetch() to automatically follow redirect responses resulting in HTTP requests to the public internet. fetch() has Fetch API semantics, not RPC semantics.

connect() method reserved but not implemented

The connect() method of the WorkerEntrypoint class is reserved for opening a socket-like connection to a Worker. This method is currently not implemented or supported.

dup and constructor method names disallowed in RPC

The method names 'dup' and 'constructor' may not be used as RPC methods on any RPC type, including WorkerEntrypoint, DurableObject, and RpcTarget. 'dup' is reserved for duplicating a stub. 'constructor' has special meaning for JavaScript classes and is not intended to be called as a method over RPC.

alarm, webSocketMessage, webSocketClose, webSocketError disallowed on WorkerEntrypoint and DurableObject

The method names 'alarm', 'webSocketMessage', 'webSocketClose', and 'webSocketError' are disallowed only on WorkerEntrypoint and DurableObject, but are allowed on RpcTarget. These methods have historically had special meaning to Durable Objects where they are used to handle certain system-generated events.

Special method semantics do not apply to RpcTarget

Method names with special semantics (like fetch, connect, alarm, webSocketMessage, webSocketClose, webSocketError) do not apply to RpcTarget. On RpcTarget, these methods work like any other RPC method.

Service type parameter in generated env

The Service type in the generated env accepts an import statement to the Worker service implementation type. For example, Service<import("../sum-worker/src/index").SumService> creates a typed binding to a remote Worker service.

RPC methods are exposed with types to client Worker

After types are generated, RPC method signatures from the remote service are fully typed in the client Worker. For example, env.SUM_SERVICE.sum method can be called with proper type checking.

Client Worker RPC call example with ExportedHandler

An example of calling an RPC method from a client Worker is: export default { async fetch(req, env, ctx): Promise<Response> { const result = await env.SUM_SERVICE.sum(1, 2); return new Response(result.toString()); }, } satisfies ExportedHandler<Env>;

Give your agent this brain