-
Notifications
You must be signed in to change notification settings - Fork 12.8k
[IN PROGRESS] Create dedicated Dynamic Workers documentation section #29019
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
Open
dinasaur404
wants to merge
15
commits into
production
Choose a base branch
from
dynamic-workers-doc
base: production
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
d224ac9
[Dynamic Workers] add documentation section
dinasaur404 47ef72c
Update src/content/docs/dynamic-workers/api-reference.mdx
dinasaur404 a47a724
Update src/content/docs/dynamic-workers/api-reference.mdx
dinasaur404 1aa0ec4
Update src/content/docs/dynamic-workers/configuration/static-assets.mdx
dinasaur404 7c91ecc
Update src/content/docs/dynamic-workers/configuration/static-assets.mdx
dinasaur404 4ef29b6
[Dynamic Workers] Rewrite bindings page with TrackedKV example and cl…
dinasaur404 a81abe7
[Dynamic Workers] Clarify egress control block behavior
dinasaur404 5300173
[Dynamic Workers] Rewrite observability page with Tail Worker walkthr…
dinasaur404 203cfa8
Update src/content/docs/dynamic-workers/getting-started.mdx
dinasaur404 2bcde58
Update src/content/docs/dynamic-workers/configuration/observability.mdx
dinasaur404 e0917ab
Update src/content/docs/dynamic-workers/index.mdx
dinasaur404 6ffd67b
[Dynamic Workers] Rewrite static assets page with KV storage and Asse…
dinasaur404 b1f9c23
[Dynamic Workers] Fix unclosed WranglerConfig block in observability …
dinasaur404 0dec1a2
[Dynamic Workers] Add Deploy to Cloudflare button to overview and get…
dinasaur404 fee9432
[Dynamic Workers] Revert sidebar.ts changes
dinasaur404 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
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
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,12 @@ | ||
| name: Dynamic Workers | ||
|
|
||
| entry: | ||
| title: Dynamic Workers | ||
| url: /dynamic-workers/ | ||
| group: Developer platform | ||
| additional_groups: [AI] | ||
|
|
||
| meta: | ||
| title: Cloudflare Dynamic Workers docs | ||
| description: Spin up isolated Workers on demand to execute code | ||
| author: "@cloudflare" |
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,195 @@ | ||||||
| --- | ||||||
| title: API reference | ||||||
| description: Reference for the Worker Loader binding and the WorkerCode object. | ||||||
| pcx_content_type: reference | ||||||
| sidebar: | ||||||
| order: 5 | ||||||
| --- | ||||||
|
|
||||||
| ## `load` | ||||||
|
|
||||||
| `load(code): WorkerStub` | ||||||
|
|
||||||
| Loads a Worker from the provided `WorkerCode` and returns a `WorkerStub` which may be used to invoke the Worker. | ||||||
|
|
||||||
| Unlike `get()`, `load()` does not cache by ID. Each call creates a fresh Worker. | ||||||
|
|
||||||
| Use `load()` when the code is always new, such as for AI-generated code, one-shot scripts, or previews where reuse does not matter. | ||||||
|
|
||||||
| ## `get` | ||||||
|
|
||||||
| `get(id, getCodeCallback): WorkerStub` | ||||||
|
|
||||||
| Loads a Worker with the given ID, returning a `WorkerStub` which may be used to invoke the Worker. | ||||||
|
|
||||||
| As a convenience, the loader implements caching of isolates. When a new ID is seen the first time, a new isolate is loaded. But the isolate may be kept warm in memory for a while. If later invocations of the loader request the same ID, the existing isolate may be returned again rather than create a new one. But there is no guarantee. A later call with the same ID may instead start a new isolate from scratch. | ||||||
|
|
||||||
| Whenever the system determines it needs to start a new isolate, and it does not already have a copy of the code cached, it invokes `getCodeCallback` to get the Worker's code. This is an async callback, so the application can load the code from remote storage if desired. The callback returns a `WorkerCode` object. | ||||||
|
|
||||||
| Because of the caching, you should ensure that the callback always returns exactly the same content when called for the same ID. If anything about the content changes, you must use a new ID. But if the content has not changed, it is best to reuse the same ID to take advantage of caching. If the `WorkerCode` is different every time, you can pass a random ID. | ||||||
|
|
||||||
| You could, for example, use IDs of the form `<worker-name>:<version-number>`, where the version number increments every time the code changes. Or you could compute IDs based on a hash of the code and config, so that any change results in a new ID. | ||||||
|
|
||||||
| `get()` returns a `WorkerStub`, which can be used to send requests to the loaded Worker. Note that the stub is returned synchronously. You do not have to await it. If the Worker is not loaded yet, requests made to the stub wait for the Worker to load before they are delivered. If loading fails, the request throws an exception. | ||||||
|
|
||||||
| It is never guaranteed that two requests go to the same isolate. Even if you use the same `WorkerStub` to make multiple requests, they could execute in different isolates. The callback passed to `loader.get()` could be called any number of times, although it is unusual for it to be called more than once. | ||||||
|
|
||||||
| ## `WorkerCode` | ||||||
|
|
||||||
| This is the structure returned by `getCodeCallback` to represent a Worker. | ||||||
|
|
||||||
| ### `compatibilityDate` | ||||||
|
|
||||||
| The [compatibility date](/workers/configuration/compatibility-dates/) for the Worker. This has the same meaning as the `compatibility_date` setting in a Wrangler config file. | ||||||
|
|
||||||
| ### `compatibilityFlags` Optional | ||||||
|
|
||||||
| An optional list of [compatibility flags](/workers/configuration/compatibility-flags/) augmenting the compatibility date. This has the same meaning as the `compatibility_flags` setting in a Wrangler config file. | ||||||
|
|
||||||
| ### `allowExperimental` Optional | ||||||
|
|
||||||
| If `true`, experimental compatibility flags are permitted in `compatibilityFlags`. To set this, the Worker calling the loader must itself have the compatibility flag `experimental` set. Experimental flags cannot be enabled in production. | ||||||
dinasaur404 marked this conversation as resolved.
Show resolved
Hide resolved
dinasaur404 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
|
|
||||||
| ### `mainModule` | ||||||
|
|
||||||
| The name of the Worker's main module. This must be one of the modules listed in `modules`. | ||||||
|
|
||||||
| ### `modules` | ||||||
|
|
||||||
| A dictionary object mapping module names to their string contents. If the module content is a plain string, the module name must have a file extension indicating its type: either `.js` or `.py`. | ||||||
|
|
||||||
| A module's content can also be specified as an object to specify its type independent from the name. The allowed objects are: | ||||||
|
|
||||||
| - `{js: string}`: A JavaScript module using ES modules syntax for imports and exports. | ||||||
| - `{cjs: string}`: A CommonJS module using `require()` syntax for imports. | ||||||
| - `{py: string}`: A Python module. | ||||||
| - `{text: string}`: An importable string value. | ||||||
| - `{data: ArrayBuffer}`: An importable `ArrayBuffer` value. | ||||||
| - `{json: object}`: An importable object. The value must be JSON-serializable. However, the value is provided as a parsed object and is delivered as a parsed object. Neither side actually sees the JSON serialization. | ||||||
|
|
||||||
| :::caution[Warning] | ||||||
|
|
||||||
| While Dynamic Workers support Python, Python Workers are much slower to start than JavaScript Workers, which may defeat some of the benefits of dynamic isolate loading. They may also be priced differently when Worker Loaders become generally available. | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Terminology mismatch — "Dynamic Isolates" does not match the "Dynamic Workers" naming used everywhere else in these docs.
Suggested change
|
||||||
|
|
||||||
| ::: | ||||||
|
|
||||||
| ### `globalOutbound` Optional | ||||||
|
|
||||||
| Controls whether the dynamic Worker has access to the network. The global `fetch()` and `connect()` functions can be blocked or redirected to isolate the Worker. | ||||||
|
|
||||||
| If `globalOutbound` is not specified, the default is to inherit the parent Worker's network access, which usually means the dynamic Worker has full access to the public Internet. | ||||||
|
|
||||||
| If `globalOutbound` is `null`, the dynamic Worker is totally cut off from the network. Both `fetch()` and `connect()` throw exceptions. | ||||||
|
|
||||||
| `globalOutbound` can also be set to any service binding, including service bindings in the parent Worker's `env` as well as loopback bindings from `ctx.exports`. | ||||||
|
|
||||||
| Using `ctx.exports` is particularly useful because it lets you customize the binding further for the specific sandbox by setting the value of `ctx.props` that should be passed back to it. The props can contain information to identify the specific dynamic Worker that made the request. | ||||||
|
|
||||||
| For example: | ||||||
|
|
||||||
| ```js | ||||||
| import { WorkerEntrypoint } from "cloudflare:workers"; | ||||||
|
|
||||||
| export class Greeter extends WorkerEntrypoint { | ||||||
| fetch(request) { | ||||||
| return new Response(`Hello, ${this.ctx.props.name}!`); | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| export default { | ||||||
| async fetch(request, env, ctx) { | ||||||
| let worker = env.LOADER.get("alice", () => { | ||||||
| return { | ||||||
| // Redirect the Worker's global outbound to send all requests | ||||||
| // to the `Greeter` class, filling in `ctx.props.name` with | ||||||
| // the name "Alice", so that it always responds "Hello, Alice!". | ||||||
| globalOutbound: ctx.exports.Greeter({ props: { name: "Alice" } }), | ||||||
|
|
||||||
| // ... code ... | ||||||
| }; | ||||||
| }); | ||||||
|
|
||||||
| return worker.getEntrypoint().fetch(request); | ||||||
| }, | ||||||
| }; | ||||||
| ``` | ||||||
|
|
||||||
| ### `env` | ||||||
|
|
||||||
| The environment object to provide to the dynamic Worker. | ||||||
|
|
||||||
| Using this, you can provide custom bindings to the Worker. | ||||||
|
|
||||||
| `env` is serialized and transferred into the dynamic Worker, where it is used directly as the value of `env` there. It may contain: | ||||||
|
|
||||||
| - [Structured clonable types](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm). | ||||||
| - [Service Bindings](/workers/runtime-apis/bindings/service-bindings/), including loopback bindings from `ctx.exports`. | ||||||
|
|
||||||
| The second point is the key to creating custom bindings. You can define a binding with any arbitrary API by defining a `WorkerEntrypoint` class implementing an RPC API, and then giving it to the dynamic Worker as a Service Binding. | ||||||
|
|
||||||
| Moreover, by using `ctx.exports` loopback bindings, you can further customize the bindings for the specific dynamic Worker by setting `ctx.props`, just as described for `globalOutbound` above. | ||||||
|
|
||||||
| ```js | ||||||
| import { WorkerEntrypoint } from "cloudflare:workers"; | ||||||
|
|
||||||
| // Implement a binding which can be called by the dynamic Worker. | ||||||
| export class Greeter extends WorkerEntrypoint { | ||||||
| greet() { | ||||||
| return `Hello, ${this.ctx.props.name}!`; | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| export default { | ||||||
| async fetch(request, env, ctx) { | ||||||
| let worker = env.LOADER.get("alice", () => { | ||||||
| return { | ||||||
| env: { | ||||||
| // Provide a binding which has a method greet() which can be called | ||||||
| // to receive a greeting. The binding knows the Worker's name. | ||||||
| GREETER: ctx.exports.Greeter({ props: { name: "Alice" } }), | ||||||
| }, | ||||||
|
|
||||||
| // ... code ... | ||||||
| }; | ||||||
| }); | ||||||
|
|
||||||
| return worker.getEntrypoint().fetch(request); | ||||||
| }, | ||||||
| }; | ||||||
| ``` | ||||||
|
|
||||||
| ### `tails` Optional | ||||||
|
|
||||||
| You may specify one or more Tail Workers which observe console logs, errors, and other details about the dynamically-loaded Worker's execution. A tail event is delivered to the Tail Worker upon completion of a request to the dynamically-loaded Worker. As always, you can implement the Tail Worker as an alternative entrypoint in your parent Worker, referring to it with `ctx.exports`. | ||||||
|
|
||||||
| ```js | ||||||
| import { WorkerEntrypoint } from "cloudflare:workers"; | ||||||
|
|
||||||
| export default { | ||||||
| async fetch(request, env, ctx) { | ||||||
| let worker = env.LOADER.get("alice", () => { | ||||||
| return { | ||||||
| // Send logs, errors, and other details to `LogTailer`. | ||||||
| // We pass `name` in `ctx.props` so that `LogTailer` knows | ||||||
| // what generated the logs. | ||||||
| tails: [ctx.exports.LogTailer({ props: { name: "alice" } })], | ||||||
|
|
||||||
| // ... code ... | ||||||
| }; | ||||||
| }); | ||||||
|
|
||||||
| return worker.getEntrypoint().fetch(request); | ||||||
| }, | ||||||
| }; | ||||||
|
|
||||||
| export class LogTailer extends WorkerEntrypoint { | ||||||
| async tail(events) { | ||||||
| let name = this.ctx.props.name; | ||||||
|
|
||||||
| await fetch(`https://example.com/submit-logs/${name}`, { | ||||||
| method: "POST", | ||||||
| body: JSON.stringify(events), | ||||||
| }); | ||||||
| } | ||||||
| } | ||||||
| ``` | ||||||
Oops, something went wrong.
Oops, something went wrong.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any of these that refers to something documented well elsewhere in the developer docs needs to link to those docs