Skip to content

Commit 3b20e5a

Browse files
docs: improve dynamic dispatch Worker documentation (#24503)
* docs: improve dynamic dispatch Worker documentation * Update src/content/docs/cloudflare-for-platforms/workers-for-platforms/get-started/dynamic-dispatch.mdx Co-authored-by: Brendan Irvine-Broque <[email protected]> --------- Co-authored-by: Brendan Irvine-Broque <[email protected]>
1 parent 5edc065 commit 3b20e5a

File tree

1 file changed

+115
-21
lines changed

1 file changed

+115
-21
lines changed

src/content/docs/cloudflare-for-platforms/workers-for-platforms/get-started/dynamic-dispatch.mdx

Lines changed: 115 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,32 +5,126 @@ sidebar:
55
order: 3
66

77
---
8+
import { Render, PackageManagers, WranglerConfig } from "~/components";
89

9-
After you have created a dispatch namespace, you can fetch any user Workers in the namespace using a dynamic dispatch Worker. The dynamic dispatch Worker has a namespace binding.
10+
A [dynamic dispatch Worker](/cloudflare-for-platforms/workers-for-platforms/reference/how-workers-for-platforms-works/#dynamic-dispatch-worker) is a specialized routing Worker that directs incoming requests to the appropriate user Workers in your dispatch namespace. Instead of using [Workers Routes](/workers/configuration/routing/routes/), dispatch Workers let you programmatically control request routing through code.
1011

11-
Use any method of routing to a namespaced Worker (reading the subdomain, request header, or lookup in a database). Ultimately you need the name of the user Worker.
1212

13-
In the following example, routing to a user Worker is done through reading the subdomain `<USER_WORKER_NAME>.example.com/*`. For example, `my-customer.example.com` will run the script uploaded to `PUT accounts/<ACCOUNT_ID>/workers/dispatch/namespaces/my-dispatch-namespace/scripts/my-customer`.
13+
![Figure 1: Workers for Platforms: Main Flow](~/assets/images/reference-architecture/programmable-platforms/programmable-platforms-1.svg)
14+
15+
16+
#### Why use a dynamic dispatch Worker?
17+
18+
* **Scale**: Allows you to route requests to millions of hostnames to different Workers, without defining [Workers Routes](/workers/configuration/routing/routes/) configuration for each one
19+
* **Custom routing logic**: Write code to determine exactly how requests should be routed. For example:
20+
* Store hostname-to-Worker mappings in [Workers KV](/kv/) and look them up dynamically
21+
* Route requests based on subdomain, path, headers, or other request properties
22+
* Use [custom metadata](/cloudflare-for-platforms/cloudflare-for-saas/domain-support/custom-metadata/) attached to [custom hostnames](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/) for routing decisions
23+
24+
### Configure the dispatch namespace binding
25+
To allow your dynamic dispatch Worker to dynamically route requests to Workers in a namespace, you need to configure a dispatch namespace [binding](/workers/runtime-apis/bindings/). This binding enables your dynamic dispatch Worker to call any user Worker within that namespace using `env.dispatcher.get()`.
26+
27+
<WranglerConfig>
28+
29+
```toml
30+
[[dispatch_namespaces]]
31+
binding = "DISPATCHER"
32+
namespace = "my-dispatch-namespace"
33+
```
34+
35+
</WranglerConfig>
36+
37+
Once the binding is configured, your dynamic dispatch Worker can route requests to any Worker in the namespace. Below are common routing patterns you can implement in your dispatcher.
38+
39+
### Routing examples
40+
41+
![Figure 2: Workers for Platforms: Main Flow](~/assets/images/reference-architecture/programmable-platforms/programmable-platforms-2.svg)
42+
43+
44+
#### KV-Based Routing
45+
Store the routing mappings in [Workers KV](/kv/). This allows you to modify your routing logic without requiring you to change or redeploy the dynamic dispatch Worker.
46+
47+
```js
48+
export default {
49+
async fetch(request, env) {
50+
try {
51+
const url = new URL(request.url);
52+
53+
// Use hostname, path, or any combination as the routing key
54+
const routingKey = url.hostname;
55+
56+
// Lookup user Worker name from KV store
57+
const userWorkerName = await env.USER_ROUTING.get(routingKey);
58+
59+
if (!userWorkerName) {
60+
return new Response('Route not configured', { status: 404 });
61+
}
62+
63+
// Optional: Cache the KV lookup result
64+
const userWorker = env.DISPATCHER.get(userWorkerName);
65+
return await userWorker.fetch(request);
66+
} catch (e) {
67+
if (e.message.startsWith('Worker not found')) {
68+
return new Response('', { status: 404 });
69+
}
70+
return new Response(e.message, { status: 500 });
71+
}
72+
}
73+
};
74+
```
75+
76+
77+
#### Subdomain-Based Routing
78+
Route subdomains to the corresponding Worker. For example, `my-customer.example.com` will route to the Worker named `my-customer` in the dispatch namespace.
1479

1580
```js
1681
export default {
17-
async fetch(request, env) {
18-
try {
19-
// parse the URL, read the subdomain
20-
let workerName = new URL(request.url).host.split('.')[0];
21-
let userWorker = env.dispatcher.get(workerName);
22-
return await userWorker.fetch(request);
23-
} catch (e) {
24-
if (e.message.startsWith('Worker not found')) {
25-
// we tried to get a worker that doesn't exist in our dispatch namespace
26-
return new Response('', { status: 404 });
27-
}
28-
29-
// this could be any other exception from `fetch()` *or* an exception
30-
// thrown by the called worker (e.g. if the dispatched worker has
31-
// `throw MyException()`, you could check for that here).
32-
return new Response(e.message, { status: 500 });
33-
}
34-
},
82+
async fetch(request, env) {
83+
try {
84+
// Extract user Worker name from subdomain
85+
// Example: customer1.example.com -> customer1
86+
const url = new URL(request.url);
87+
const userWorkerName = url.hostname.split('.')[0];
88+
89+
// Get user Worker from dispatch namespace
90+
const userWorker = env.DISPATCHER.get(userWorkerName);
91+
return await userWorker.fetch(request);
92+
} catch (e) {
93+
if (e.message.startsWith('Worker not found')) {
94+
// User Worker doesn't exist in dispatch namespace
95+
return new Response('', { status: 404 });
96+
}
97+
// Could be any other exception from fetch() or from the dispatched Worker
98+
return new Response(e.message, { status: 500 });
99+
}
100+
}
35101
};
36102
```
103+
#### Path-Based routing
104+
Route URL paths to the corresponding Worker. For example, `example.com/customer-1` will route to the Worker named `customer-1` in the dispatch namespace.
105+
106+
```js
107+
export default {
108+
async fetch(request, env) {
109+
try {
110+
const url = new URL(request.url);
111+
const pathParts = url.pathname.split('/').filter(Boolean);
112+
113+
if (pathParts.length === 0) {
114+
return new Response('Invalid path', { status: 400 });
115+
}
116+
117+
// example.com/customer-1 -> routes to 'customer-1' worker
118+
const userWorkerName = pathParts[0];
119+
120+
const userWorker = env.DISPATCHER.get(userWorkerName);
121+
return await userWorker.fetch(request);
122+
} catch (e) {
123+
if (e.message.startsWith('Worker not found')) {
124+
return new Response('', { status: 404 });
125+
}
126+
return new Response(e.message, { status: 500 });
127+
}
128+
}
129+
};
130+
```

0 commit comments

Comments
 (0)