From f174ad0cbd39f674c90d1e3eb418738ae16beebe Mon Sep 17 00:00:00 2001 From: Thomas Gauvin Date: Thu, 24 Sep 2026 21:50:11 -0400 Subject: [PATCH 01/16] [Containers] Prepare independently reviewed raw API examples --- .../containers/examples/container-backend.mdx | 142 +++++++++++++++++- src/content/docs/containers/examples/cron.mdx | 110 ++++++++++++-- .../docs/containers/examples/stateless.mdx | 94 +++++++++++- .../docs/containers/examples/status-hooks.mdx | 91 ++++++++++- .../docs/containers/examples/websocket.mdx | 93 +++++++++++- 5 files changed, 493 insertions(+), 37 deletions(-) diff --git a/src/content/docs/containers/examples/container-backend.mdx b/src/content/docs/containers/examples/container-backend.mdx index fc458f7461a..be45a245fa2 100644 --- a/src/content/docs/containers/examples/container-backend.mdx +++ b/src/content/docs/containers/examples/container-backend.mdx @@ -10,7 +10,13 @@ products: - containers --- -import { WranglerConfig, Details } from "~/components"; +import { + WranglerConfig, + Details, + TabItem, + Tabs, + TypeScriptExample, +} from "~/components"; A common pattern is to serve a static frontend application (e.g., React, Vue, Svelte) using Static Assets, then pass backend requests to a containerized backend application. @@ -25,8 +31,9 @@ For a full example, see the [Static Frontend + Container Backend Template](https ```json { - "name": "cron-container", + "name": "static-frontend-container-backend", "main": "src/index.ts", + "compatibility_date": "$today", "assets": { "directory": "./dist", "binding": "ASSETS" @@ -138,18 +145,113 @@ Your Worker needs to be able to both serve static assets and route requests to t In this case, we will pass requests to one of three container instances if the route starts with `/api`, and all other requests will be served as static assets. -```javascript +For the direct API example, expose `GET /health` on port 8080. Return a successful response only when the backend is ready. + + + + + +```ts +import { DurableObject } from "cloudflare:workers"; + +const INSTANCE_COUNT = 3; + +interface Env { + ASSETS: Fetcher; + BACKEND: DurableObjectNamespace; +} + +export class Backend extends DurableObject { + private ready: Promise | undefined; + + async fetch(request: Request): Promise { + const container = this.ctx.container!; + if (!container.running) { + this.ready = undefined; + } + this.ready ??= this.startAndWaitForPort().catch((error: unknown) => { + this.ready = undefined; + throw error; + }); + await this.ready; + + const url = new URL(request.url); + url.protocol = "http:"; + url.host = "container"; + const forwarded = new Request(url, request); + forwarded.headers.delete("host"); + return container.getTcpPort(8080).fetch(forwarded); + } + + private async startAndWaitForPort(): Promise { + const container = this.ctx.container!; + await container.setInactivityTimeout(2 * 60 * 60 * 1000); + if (!container.running) { + container.start(); + } + this.ctx.waitUntil( + container + .monitor() + .then(() => console.log("Backend container exited")) + .catch((error: unknown) => + console.error("Backend container errored:", error), + ), + ); + + const port = container.getTcpPort(8080); + let lastError: unknown; + for (let attempt = 0; attempt < 100; attempt++) { + try { + const response = await port.fetch("http://container/health"); + if (!response.ok) { + throw new Error(`Health check returned ${response.status}`); + } + return; + } catch (error) { + lastError = error; + await scheduler.wait(200); + } + } + throw new Error("Backend did not become ready on port 8080", { + cause: lastError, + }); + } +} + +export default { + async fetch(request: Request, env: Env): Promise { + if (new URL(request.url).pathname.startsWith("/api")) { + const index = Math.floor(Math.random() * INSTANCE_COUNT); + return env.BACKEND.getByName(`instance-${index}`).fetch(request); + } + + return env.ASSETS.fetch(request); + }, +}; +``` + + + + + + +```ts import { Container, getRandom } from "@cloudflare/containers"; const INSTANCE_COUNT = 3; -class Backend extends Container { +interface Env { + ASSETS: Fetcher; + BACKEND: DurableObjectNamespace; +} + +export class Backend extends Container { defaultPort = 8080; // pass requests to port 8080 in the container sleepAfter = "2h"; // only sleep a container if it hasn't gotten requests in 2 hours } export default { - async fetch(request, env) { + async fetch(request: Request, env: Env): Promise { const url = new URL(request.url); if (url.pathname.startsWith("/api")) { const containerInstance = await getRandom(env.BACKEND, INSTANCE_COUNT); @@ -160,10 +262,13 @@ export default { }, }; ``` + + + + :::note -This example uses `getRandom`, which randomly selects one of a fixed number of Container -instances for each request. +Both examples randomly select one of a fixed number of Container instances for each request. The `Container` class provides `getRandom()` as a helper. In the future, we will provide improved latency-aware load balancing and autoscaling. @@ -188,7 +293,7 @@ import ( "net/http" ) -func handler(w http.ResponseWriter, r \*http.Request) { +func handler(w http.ResponseWriter, r *http.Request) { widgets := []map[string]interface{}{ {"id": 1, "name": "Widget A"}, {"id": 2, "name": "Sprocket B"}, @@ -202,6 +307,9 @@ func handler(w http.ResponseWriter, r \*http.Request) { } func main() { + http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + }) http.HandleFunc("/api/widgets", handler) log.Fatal(http.ListenAndServe(":8080", nil)) } @@ -209,3 +317,21 @@ func main() { ``` + +The health endpoint lets the Worker wait for the backend before forwarding requests. Build the backend image with this Dockerfile in the project root: + +
+ +```dockerfile +FROM golang:1.25-alpine AS build +WORKDIR /app +COPY server.go . +RUN CGO_ENABLED=0 go build -o /server server.go + +FROM alpine:3.20 +COPY --from=build /server /server +EXPOSE 8080 +CMD ["/server"] +``` + +
diff --git a/src/content/docs/containers/examples/cron.mdx b/src/content/docs/containers/examples/cron.mdx index beb5c71d036..f048ced8708 100644 --- a/src/content/docs/containers/examples/cron.mdx +++ b/src/content/docs/containers/examples/cron.mdx @@ -10,7 +10,7 @@ products: - containers --- -import { WranglerConfig } from "~/components"; +import { TabItem, Tabs, TypeScriptExample, WranglerConfig } from "~/components"; To launch a container on a schedule, you can use a Workers [Cron Trigger](/workers/configuration/cron-triggers/). @@ -20,10 +20,11 @@ Use a cron expression in your Wrangler config to specify the schedule: -```json +```jsonc { "name": "cron-container", "main": "src/index.ts", + "compatibility_date": "$today", "triggers": { "crons": [ "*/2 * * * *" // Run every 2 minutes @@ -54,10 +55,85 @@ Use a cron expression in your Wrangler config to specify the schedule: -Then in your Worker, call your Container from the "scheduled" handler: +Then call the Container from the `scheduled()` handler in the Worker. The raw API example expects the Container to expose a `GET /health` endpoint that returns success when ready and a `POST /run` endpoint that starts the scheduled task. + + + + ```ts -import { Container, getContainer } from '@cloudflare/containers'; +import { DurableObject } from "cloudflare:workers"; + +interface Env { + CRON_CONTAINER: DurableObjectNamespace; +} + +export class CronContainer extends DurableObject { + private currentRun: Promise | undefined; + + run(startTime: string): Promise { + this.currentRun ??= this.runOnce(startTime).finally(() => { + this.currentRun = undefined; + }); + return this.currentRun; + } + + private async runOnce(startTime: string): Promise { + const container = this.ctx.container!; + await container.setInactivityTimeout(10_000); + + if (!container.running) { + container.start(); + } + + const port = container.getTcpPort(8080); + let lastError: unknown; + for (let attempt = 0; attempt < 100; attempt++) { + try { + const response = await port.fetch("http://container/health"); + if (!response.ok) { + throw new Error(`Health check returned ${response.status}`); + } + lastError = undefined; + break; + } catch (error) { + lastError = error; + await scheduler.wait(200); + } + } + if (lastError) { + throw lastError; + } + + const response = await port.fetch("http://container/run", { + method: "POST", + body: JSON.stringify({ startTime }), + headers: { "content-type": "application/json" }, + }); + if (!response.ok) { + throw new Error(`Container returned ${response.status}`); + } + } +} + +export default { + async fetch(): Promise { + return new Response("This Worker runs a scheduled Container task."); + }, + + async scheduled(_controller: ScheduledController, env: Env): Promise { + await env.CRON_CONTAINER.getByName("cron").run(new Date().toISOString()); + }, +}; +``` + + + + + + +```ts +import { Container, getContainer } from "@cloudflare/containers"; export class CronContainer extends Container { sleepAfter = '10s'; @@ -72,17 +148,21 @@ export class CronContainer extends Container { } export default { - async fetch(): Promise { - return new Response("This Worker runs a cron job to execute a container on a schedule."); - }, - - async scheduled(_controller: any, env: { CRON_CONTAINER: DurableObjectNamespace }) { - let container = getContainer(env.CRON_CONTAINER); - await container.start({ - envVars: { + async fetch(): Promise { + return new Response("This Worker runs a cron job to execute a container on a schedule."); + }, + + async scheduled(_controller: ScheduledController, env: { CRON_CONTAINER: DurableObjectNamespace }) { + const container = getContainer(env.CRON_CONTAINER); + await container.start({ + envVars: { MESSAGE: "Start Time: " + new Date().toISOString(), - } - }) - }, + }, + }); + }, }; ``` + + + + diff --git a/src/content/docs/containers/examples/stateless.mdx b/src/content/docs/containers/examples/stateless.mdx index 8cf6275a0df..59c50223e45 100644 --- a/src/content/docs/containers/examples/stateless.mdx +++ b/src/content/docs/containers/examples/stateless.mdx @@ -10,14 +10,97 @@ products: - containers --- -To simply proxy requests to one of multiple instances of a container, you can use the `getRandom` function: +import { TabItem, Tabs, TypeScriptExample } from "~/components"; +To proxy requests across a fixed number of Container instances, select an instance name and forward the request through its Durable Object. + +For the direct API example, expose a `GET /health` endpoint on port 8080 that returns a successful response when the application is ready. + + + + + +```ts +import { DurableObject } from "cloudflare:workers"; + +const INSTANCE_COUNT = 3; + +interface Env { + BACKEND: DurableObjectNamespace; +} + +export class Backend extends DurableObject { + private ready: Promise | undefined; + + async fetch(request: Request): Promise { + const container = this.ctx.container!; + if (!container.running) { + this.ready = undefined; + } + this.ready ??= this.startAndWaitForPort().catch((error: unknown) => { + this.ready = undefined; + throw error; + }); + await this.ready; + + const url = new URL(request.url); + url.protocol = "http:"; + url.host = "container"; + const forwarded = new Request(url, request); + forwarded.headers.delete("host"); + return container.getTcpPort(8080).fetch(forwarded); + } + + private async startAndWaitForPort(): Promise { + const container = this.ctx.container!; + await container.setInactivityTimeout(2 * 60 * 60 * 1000); + if (!container.running) { + container.start(); + } + + const port = container.getTcpPort(8080); + let lastError: unknown; + for (let attempt = 0; attempt < 100; attempt++) { + try { + const response = await port.fetch("http://container/health"); + if (!response.ok) { + throw new Error(`Health check returned ${response.status}`); + } + return; + } catch (error) { + lastError = error; + await scheduler.wait(200); + } + } + throw new Error("Container did not become ready on port 8080", { + cause: lastError, + }); + } +} + +export default { + async fetch(request: Request, env: Env): Promise { + const index = Math.floor(Math.random() * INSTANCE_COUNT); + return env.BACKEND.getByName(`instance-${index}`).fetch(request); + }, +}; +``` + + + + + + ```ts import { Container, getRandom } from "@cloudflare/containers"; const INSTANCE_COUNT = 3; -class Backend extends Container { +interface Env { + BACKEND: DurableObjectNamespace; +} + +export class Backend extends Container { defaultPort = 8080; sleepAfter = "2h"; } @@ -29,10 +112,13 @@ export default { }, }; ``` + + + + :::note -This example uses `getRandom`, which randomly selects one of a fixed number of Container -instances for each request. +Both examples randomly select one of a fixed number of Container instances for each request. The `Container` class provides `getRandom()` as a helper. In the future, we will provide improved latency-aware load balancing and autoscaling. diff --git a/src/content/docs/containers/examples/status-hooks.mdx b/src/content/docs/containers/examples/status-hooks.mdx index 3d38fcd9e2b..d3993f54c1d 100644 --- a/src/content/docs/containers/examples/status-hooks.mdx +++ b/src/content/docs/containers/examples/status-hooks.mdx @@ -11,11 +11,86 @@ products: - workers --- -When a Container starts, stops, becomes idle, and errors, it can trigger code execution in a Worker -that has defined status hooks on the `Container` class. Refer to the [Container class lifecycle hooks](/containers/api/container-class/#lifecycle-hooks) for more details. +import { TabItem, Tabs, TypeScriptExample } from "~/components"; +Use `monitor()` with the Durable Object Container API to run code after the Container exits or errors. The `Container` class adds named lifecycle hooks and an inactivity callback. + +For the direct API example, expose `GET /health` on port 4000. Return a successful response once the application is ready. + + + + + +```ts +import { DurableObject } from "cloudflare:workers"; + +interface Env {} + +export class MyContainer extends DurableObject { + private ready: Promise | undefined; + + async fetch(request: Request): Promise { + const container = this.ctx.container!; + if (!container.running) { + this.ready = undefined; + } + this.ready ??= this.startAndMonitor().catch((error: unknown) => { + this.ready = undefined; + throw error; + }); + await this.ready; + + const url = new URL(request.url); + url.protocol = "http:"; + url.host = "container"; + const forwarded = new Request(url, request); + forwarded.headers.delete("host"); + return container.getTcpPort(4000).fetch(forwarded); + } + + private async startAndMonitor(): Promise { + const container = this.ctx.container!; + await container.setInactivityTimeout(5 * 60 * 1000); + if (!container.running) { + container.start(); + } + + this.ctx.waitUntil( + container + .monitor() + .then(() => console.log("Container stopped")) + .catch((error: unknown) => console.error("Container error:", error)), + ); + + const port = container.getTcpPort(4000); + let lastError: unknown; + for (let attempt = 0; attempt < 100; attempt++) { + try { + const response = await port.fetch("http://container/health"); + if (!response.ok) { + throw new Error(`Health check returned ${response.status}`); + } + console.log("Container successfully started"); + return; + } catch (error) { + lastError = error; + await scheduler.wait(200); + } + } + throw new Error("Container did not become ready on port 4000", { + cause: lastError, + }); + } +} +``` + + + + + + ```ts -import { Container } from "@cloudflare/containers"; +import { Container, type StopParams } from "@cloudflare/containers"; export class MyContainer extends Container { defaultPort = 4000; @@ -25,7 +100,7 @@ export class MyContainer extends Container { console.log("Container successfully started"); } - override onStop(stopParams) { + override onStop(stopParams: StopParams) { if (stopParams.exitCode === 0) { console.log("Container stopped gracefully"); } else { @@ -40,8 +115,14 @@ export class MyContainer extends Container { await this.stop(); } - override onError(error: string) { + override onError(error: unknown) { console.log("Container error:", error); } } ``` + + + + + +The `monitor()` promise in the raw API does not include an exit code or stop reason. The `setInactivityTimeout()` method does not invoke a callback when the timeout expires. Use the [`Container` class lifecycle hooks](/containers/api/container-class/#lifecycle-hooks) when you need those higher-level events. diff --git a/src/content/docs/containers/examples/websocket.mdx b/src/content/docs/containers/examples/websocket.mdx index 66a5968d448..edb32afb633 100644 --- a/src/content/docs/containers/examples/websocket.mdx +++ b/src/content/docs/containers/examples/websocket.mdx @@ -10,24 +10,107 @@ products: - containers --- -WebSocket requests are automatically forwarded to a container using the default `fetch` -method on the `Container` class: +import { TabItem, Tabs, TypeScriptExample } from "~/components"; -```js +Forward an incoming WebSocket upgrade request through the Durable Object to the listening port on the Container. + +For the direct API example, expose a `GET /health` endpoint on port 8080 that returns a successful response when the application is ready. Keep the WebSocket endpoint separate from the health check. + + + + + +```ts +import { DurableObject } from "cloudflare:workers"; + +interface Env { + MY_CONTAINER: DurableObjectNamespace; +} + +export class MyContainer extends DurableObject { + private ready: Promise | undefined; + + async fetch(request: Request): Promise { + const container = this.ctx.container!; + if (!container.running) { + this.ready = undefined; + } + this.ready ??= this.startAndWaitForPort().catch((error: unknown) => { + this.ready = undefined; + throw error; + }); + await this.ready; + + const url = new URL(request.url); + url.protocol = "http:"; + url.host = "container"; + const forwarded = new Request(url, request); + forwarded.headers.delete("host"); + return container.getTcpPort(8080).fetch(forwarded); + } + + private async startAndWaitForPort(): Promise { + const container = this.ctx.container!; + await container.setInactivityTimeout(2 * 60 * 1000); + if (!container.running) { + container.start(); + } + + const port = container.getTcpPort(8080); + let lastError: unknown; + for (let attempt = 0; attempt < 100; attempt++) { + try { + const response = await port.fetch("http://container/health"); + if (!response.ok) { + throw new Error(`Health check returned ${response.status}`); + } + return; + } catch (error) { + lastError = error; + await scheduler.wait(200); + } + } + throw new Error("Container did not become ready on port 8080", { + cause: lastError, + }); + } +} + +export default { + fetch(request: Request, env: Env): Promise { + return env.MY_CONTAINER.getByName("default").fetch(request); + }, +}; +``` + + + + + + +```ts import { Container, getContainer } from "@cloudflare/containers"; -export class MyContainer extends Container { +interface Env { + MY_CONTAINER: DurableObjectNamespace; +} + +export class MyContainer extends Container { defaultPort = 8080; sleepAfter = "2m"; } export default { - async fetch(request, env) { + async fetch(request: Request, env: Env): Promise { // gets default instance and forwards websocket from outside Worker return getContainer(env.MY_CONTAINER).fetch(request); }, }; ``` + + + + View a full example in the [Container class repository](https://github.com/cloudflare/containers/tree/main/examples/websocket). {/* TODO: Add more advanced examples - like kicking off a WS request then passing messages to container from the WS */} From 51ef994c90cadffdce0b66991960b092c217f0cb Mon Sep 17 00:00:00 2001 From: Thomas Gauvin Date: Thu, 24 Sep 2026 22:55:29 -0400 Subject: [PATCH 02/16] [Containers] Use direct API terminology in status example --- src/content/docs/containers/examples/status-hooks.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/docs/containers/examples/status-hooks.mdx b/src/content/docs/containers/examples/status-hooks.mdx index d3993f54c1d..7115c3a9cf8 100644 --- a/src/content/docs/containers/examples/status-hooks.mdx +++ b/src/content/docs/containers/examples/status-hooks.mdx @@ -125,4 +125,4 @@ export class MyContainer extends Container { -The `monitor()` promise in the raw API does not include an exit code or stop reason. The `setInactivityTimeout()` method does not invoke a callback when the timeout expires. Use the [`Container` class lifecycle hooks](/containers/api/container-class/#lifecycle-hooks) when you need those higher-level events. +The `monitor()` promise in the direct API does not include an exit code or stop reason. The `setInactivityTimeout()` method does not invoke a callback when the timeout expires. Use the [`Container` class lifecycle hooks](/containers/api/container-class/#lifecycle-hooks) when you need those events. From 0879da4193842ad68cebbe880a2eb0fe4c2aa786 Mon Sep 17 00:00:00 2001 From: Thomas Gauvin Date: Tue, 29 Sep 2026 16:23:42 -0400 Subject: [PATCH 03/16] [Containers] Remove forward-looking and raw API wording --- src/content/docs/containers/examples/container-backend.mdx | 5 +---- src/content/docs/containers/examples/cron.mdx | 2 +- src/content/docs/containers/examples/stateless.mdx | 5 +---- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/content/docs/containers/examples/container-backend.mdx b/src/content/docs/containers/examples/container-backend.mdx index be45a245fa2..9981415bef3 100644 --- a/src/content/docs/containers/examples/container-backend.mdx +++ b/src/content/docs/containers/examples/container-backend.mdx @@ -270,10 +270,7 @@ export default { :::note Both examples randomly select one of a fixed number of Container instances for each request. The `Container` class provides `getRandom()` as a helper. -In the future, we will provide improved latency-aware load balancing and autoscaling. - -This will make scaling stateless instances simple and routing more efficient. See the -[autoscaling documentation](/containers/configuration/scaling-and-routing) for more details. +See the [autoscaling documentation](/containers/configuration/scaling-and-routing) for more details about scaling stateless instances and routing. ::: ## Define a backend container diff --git a/src/content/docs/containers/examples/cron.mdx b/src/content/docs/containers/examples/cron.mdx index f048ced8708..d3145111d35 100644 --- a/src/content/docs/containers/examples/cron.mdx +++ b/src/content/docs/containers/examples/cron.mdx @@ -55,7 +55,7 @@ Use a cron expression in your Wrangler config to specify the schedule:
-Then call the Container from the `scheduled()` handler in the Worker. The raw API example expects the Container to expose a `GET /health` endpoint that returns success when ready and a `POST /run` endpoint that starts the scheduled task. +Then call the Container from the `scheduled()` handler in the Worker. In the Durable Object Container API example, the Worker polls `GET /health` until the application is ready, then sends `POST /run` to start the scheduled task. diff --git a/src/content/docs/containers/examples/stateless.mdx b/src/content/docs/containers/examples/stateless.mdx index 59c50223e45..a6940b5fc57 100644 --- a/src/content/docs/containers/examples/stateless.mdx +++ b/src/content/docs/containers/examples/stateless.mdx @@ -120,8 +120,5 @@ export default { :::note Both examples randomly select one of a fixed number of Container instances for each request. The `Container` class provides `getRandom()` as a helper. -In the future, we will provide improved latency-aware load balancing and autoscaling. - -This will make scaling stateless instances simple and routing more efficient. See the -[autoscaling documentation](/containers/configuration/scaling-and-routing) for more details. +See the [autoscaling documentation](/containers/configuration/scaling-and-routing) for more details about scaling stateless instances and routing. ::: From 8a4d836d585eb34d5771957575e9e2f15bfa2bdc Mon Sep 17 00:00:00 2001 From: Thomas Gauvin Date: Tue, 29 Sep 2026 16:46:57 -0400 Subject: [PATCH 04/16] [Containers] Explain health check readiness --- src/content/docs/containers/examples/container-backend.mdx | 2 +- src/content/docs/containers/examples/stateless.mdx | 2 +- src/content/docs/containers/examples/websocket.mdx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/content/docs/containers/examples/container-backend.mdx b/src/content/docs/containers/examples/container-backend.mdx index 9981415bef3..587e131bd9b 100644 --- a/src/content/docs/containers/examples/container-backend.mdx +++ b/src/content/docs/containers/examples/container-backend.mdx @@ -145,7 +145,7 @@ Your Worker needs to be able to both serve static assets and route requests to t In this case, we will pass requests to one of three container instances if the route starts with `/api`, and all other requests will be served as static assets. -For the direct API example, expose `GET /health` on port 8080. Return a successful response only when the backend is ready. +Because `container.start()` does not wait for readiness, the Durable Object Container API example polls `GET /health` on port 8080 before forwarding requests. diff --git a/src/content/docs/containers/examples/stateless.mdx b/src/content/docs/containers/examples/stateless.mdx index a6940b5fc57..5b7609e4f76 100644 --- a/src/content/docs/containers/examples/stateless.mdx +++ b/src/content/docs/containers/examples/stateless.mdx @@ -14,7 +14,7 @@ import { TabItem, Tabs, TypeScriptExample } from "~/components"; To proxy requests across a fixed number of Container instances, select an instance name and forward the request through its Durable Object. -For the direct API example, expose a `GET /health` endpoint on port 8080 that returns a successful response when the application is ready. +Because `container.start()` does not wait for readiness, the Durable Object Container API example polls `GET /health` on port 8080 before forwarding requests. diff --git a/src/content/docs/containers/examples/websocket.mdx b/src/content/docs/containers/examples/websocket.mdx index edb32afb633..90cd78dc9e1 100644 --- a/src/content/docs/containers/examples/websocket.mdx +++ b/src/content/docs/containers/examples/websocket.mdx @@ -14,7 +14,7 @@ import { TabItem, Tabs, TypeScriptExample } from "~/components"; Forward an incoming WebSocket upgrade request through the Durable Object to the listening port on the Container. -For the direct API example, expose a `GET /health` endpoint on port 8080 that returns a successful response when the application is ready. Keep the WebSocket endpoint separate from the health check. +Because `container.start()` does not wait for readiness, the Durable Object Container API example polls `GET /health` on port 8080 before forwarding requests. Keep the WebSocket endpoint separate from the health check. From e88ea96c1732b0ef199f97fd9a43a6ef554a5589 Mon Sep 17 00:00:00 2001 From: Thomas Gauvin Date: Tue, 29 Sep 2026 16:51:21 -0400 Subject: [PATCH 05/16] [Containers] Rename external examples link --- .../docs/containers/examples/durable-object-interface.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/docs/containers/examples/durable-object-interface.mdx b/src/content/docs/containers/examples/durable-object-interface.mdx index f957451fa12..2b3c2663a36 100644 --- a/src/content/docs/containers/examples/durable-object-interface.mdx +++ b/src/content/docs/containers/examples/durable-object-interface.mdx @@ -2,7 +2,7 @@ summary: Various examples calling Containers directly from Durable Objects pcx_content_type: example -title: Using Durable Objects Directly +title: More examples external_link: https://github.com/cloudflare/containers-demos sidebar: order: 10 From d4fec5fa3baea88bd404a39986b9bcff0d16b162 Mon Sep 17 00:00:00 2001 From: Thomas Gauvin Date: Tue, 29 Sep 2026 16:52:23 -0400 Subject: [PATCH 06/16] [Containers] Clarify WebSocket readiness check --- src/content/docs/containers/examples/websocket.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/docs/containers/examples/websocket.mdx b/src/content/docs/containers/examples/websocket.mdx index 90cd78dc9e1..0e89a385c9a 100644 --- a/src/content/docs/containers/examples/websocket.mdx +++ b/src/content/docs/containers/examples/websocket.mdx @@ -14,7 +14,7 @@ import { TabItem, Tabs, TypeScriptExample } from "~/components"; Forward an incoming WebSocket upgrade request through the Durable Object to the listening port on the Container. -Because `container.start()` does not wait for readiness, the Durable Object Container API example polls `GET /health` on port 8080 before forwarding requests. Keep the WebSocket endpoint separate from the health check. +Because `container.start()` does not wait for readiness, this example polls `GET /health` before forwarding requests. Keep the WebSocket endpoint separate from the health check. From 71ca8c46f131b0207db8f067cd8bcbd6ea4a49a3 Mon Sep 17 00:00:00 2001 From: Thomas Gauvin Date: Tue, 29 Sep 2026 16:53:59 -0400 Subject: [PATCH 07/16] [Containers] Standardize readiness wording --- src/content/docs/containers/examples/container-backend.mdx | 2 +- src/content/docs/containers/examples/cron.mdx | 2 +- src/content/docs/containers/examples/stateless.mdx | 2 +- src/content/docs/containers/examples/status-hooks.mdx | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/content/docs/containers/examples/container-backend.mdx b/src/content/docs/containers/examples/container-backend.mdx index 587e131bd9b..d786c27eb33 100644 --- a/src/content/docs/containers/examples/container-backend.mdx +++ b/src/content/docs/containers/examples/container-backend.mdx @@ -145,7 +145,7 @@ Your Worker needs to be able to both serve static assets and route requests to t In this case, we will pass requests to one of three container instances if the route starts with `/api`, and all other requests will be served as static assets. -Because `container.start()` does not wait for readiness, the Durable Object Container API example polls `GET /health` on port 8080 before forwarding requests. +Because `container.start()` does not wait for readiness, this example polls `GET /health` before forwarding requests. diff --git a/src/content/docs/containers/examples/cron.mdx b/src/content/docs/containers/examples/cron.mdx index d3145111d35..629a2fb28ae 100644 --- a/src/content/docs/containers/examples/cron.mdx +++ b/src/content/docs/containers/examples/cron.mdx @@ -55,7 +55,7 @@ Use a cron expression in your Wrangler config to specify the schedule: -Then call the Container from the `scheduled()` handler in the Worker. In the Durable Object Container API example, the Worker polls `GET /health` until the application is ready, then sends `POST /run` to start the scheduled task. +Then call the Container from the `scheduled()` handler in the Worker. Because `container.start()` does not wait for readiness, this example polls `GET /health` before sending `POST /run` to start the scheduled task. diff --git a/src/content/docs/containers/examples/stateless.mdx b/src/content/docs/containers/examples/stateless.mdx index 5b7609e4f76..873753c17e3 100644 --- a/src/content/docs/containers/examples/stateless.mdx +++ b/src/content/docs/containers/examples/stateless.mdx @@ -14,7 +14,7 @@ import { TabItem, Tabs, TypeScriptExample } from "~/components"; To proxy requests across a fixed number of Container instances, select an instance name and forward the request through its Durable Object. -Because `container.start()` does not wait for readiness, the Durable Object Container API example polls `GET /health` on port 8080 before forwarding requests. +Because `container.start()` does not wait for readiness, this example polls `GET /health` before forwarding requests. diff --git a/src/content/docs/containers/examples/status-hooks.mdx b/src/content/docs/containers/examples/status-hooks.mdx index 7115c3a9cf8..81e7978209b 100644 --- a/src/content/docs/containers/examples/status-hooks.mdx +++ b/src/content/docs/containers/examples/status-hooks.mdx @@ -15,7 +15,7 @@ import { TabItem, Tabs, TypeScriptExample } from "~/components"; Use `monitor()` with the Durable Object Container API to run code after the Container exits or errors. The `Container` class adds named lifecycle hooks and an inactivity callback. -For the direct API example, expose `GET /health` on port 4000. Return a successful response once the application is ready. +Because `container.start()` does not wait for readiness, this example polls `GET /health` before forwarding requests. From 982bddc8effd54bd18b6b04674d8c215ae9f9aff Mon Sep 17 00:00:00 2001 From: Thomas Gauvin Date: Tue, 29 Sep 2026 17:10:39 -0400 Subject: [PATCH 08/16] [Containers] Enable observability in example configs --- src/content/docs/containers/examples/container-backend.mdx | 3 +++ src/content/docs/containers/examples/cron.mdx | 3 +++ src/content/docs/containers/examples/env-vars-and-secrets.mdx | 3 +++ 3 files changed, 9 insertions(+) diff --git a/src/content/docs/containers/examples/container-backend.mdx b/src/content/docs/containers/examples/container-backend.mdx index d786c27eb33..5687ed84ff0 100644 --- a/src/content/docs/containers/examples/container-backend.mdx +++ b/src/content/docs/containers/examples/container-backend.mdx @@ -34,6 +34,9 @@ For a full example, see the [Static Frontend + Container Backend Template](https "name": "static-frontend-container-backend", "main": "src/index.ts", "compatibility_date": "$today", + "observability": { + "enabled": true + }, "assets": { "directory": "./dist", "binding": "ASSETS" diff --git a/src/content/docs/containers/examples/cron.mdx b/src/content/docs/containers/examples/cron.mdx index 629a2fb28ae..eaad2f9ad93 100644 --- a/src/content/docs/containers/examples/cron.mdx +++ b/src/content/docs/containers/examples/cron.mdx @@ -25,6 +25,9 @@ Use a cron expression in your Wrangler config to specify the schedule: "name": "cron-container", "main": "src/index.ts", "compatibility_date": "$today", + "observability": { + "enabled": true + }, "triggers": { "crons": [ "*/2 * * * *" // Run every 2 minutes diff --git a/src/content/docs/containers/examples/env-vars-and-secrets.mdx b/src/content/docs/containers/examples/env-vars-and-secrets.mdx index 4dfa0e739bf..56e96741ab1 100644 --- a/src/content/docs/containers/examples/env-vars-and-secrets.mdx +++ b/src/content/docs/containers/examples/env-vars-and-secrets.mdx @@ -81,6 +81,9 @@ in Wrangler configuration. ```json { "name": "my-container-worker", + "observability": { + "enabled": true + }, "vars": { "ENV_VAR": "my-env-var" }, From efcb1812c78a4bf65f5f4186c988125cf670acf7 Mon Sep 17 00:00:00 2001 From: Thomas Gauvin Date: Tue, 29 Sep 2026 17:21:41 -0400 Subject: [PATCH 09/16] [Containers] Clarify stateless health check requirement --- src/content/docs/containers/examples/stateless.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/content/docs/containers/examples/stateless.mdx b/src/content/docs/containers/examples/stateless.mdx index 873753c17e3..285fc1815ca 100644 --- a/src/content/docs/containers/examples/stateless.mdx +++ b/src/content/docs/containers/examples/stateless.mdx @@ -14,7 +14,7 @@ import { TabItem, Tabs, TypeScriptExample } from "~/components"; To proxy requests across a fixed number of Container instances, select an instance name and forward the request through its Durable Object. -Because `container.start()` does not wait for readiness, this example polls `GET /health` before forwarding requests. +`container.start()` returns before the container is ready. The Durable Object Container API example polls `GET /health` on port `8080` before forwarding requests. The container must return a successful response only when it is ready to receive traffic. @@ -120,5 +120,5 @@ export default { :::note Both examples randomly select one of a fixed number of Container instances for each request. The `Container` class provides `getRandom()` as a helper. -See the [autoscaling documentation](/containers/configuration/scaling-and-routing) for more details about scaling stateless instances and routing. +See the [autoscaling documentation](/containers/configuration/scaling-and-routing/) for more details about scaling stateless instances and routing. ::: From c446deba1deebef222436b680fcc289cfdc90fd2 Mon Sep 17 00:00:00 2001 From: Thomas Gauvin Date: Tue, 29 Sep 2026 17:24:24 -0400 Subject: [PATCH 10/16] [Containers] Move class example links into tabs --- src/content/docs/containers/examples/container-backend.mdx | 4 ++-- src/content/docs/containers/examples/cron.mdx | 4 ++-- src/content/docs/containers/examples/websocket.mdx | 3 ++- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/content/docs/containers/examples/container-backend.mdx b/src/content/docs/containers/examples/container-backend.mdx index 5687ed84ff0..7d9d5ea9aac 100644 --- a/src/content/docs/containers/examples/container-backend.mdx +++ b/src/content/docs/containers/examples/container-backend.mdx @@ -24,8 +24,6 @@ then pass backend requests to a containerized backend application. In this example, we'll show an example using a simple `index.html` file served as a static asset, but you can select from one of many frontend frameworks. See our [Workers framework examples](/workers/framework-guides/web-apps/) for more information. -For a full example, see the [Static Frontend + Container Backend Template](https://github.com/mikenomitch/static-frontend-container-backend). - ## Configure Static Assets and a Container @@ -267,6 +265,8 @@ export default { ``` +For a full Container class example, see the [Static Frontend + Container Backend Template](https://github.com/mikenomitch/static-frontend-container-backend). + diff --git a/src/content/docs/containers/examples/cron.mdx b/src/content/docs/containers/examples/cron.mdx index eaad2f9ad93..a8c477ab40a 100644 --- a/src/content/docs/containers/examples/cron.mdx +++ b/src/content/docs/containers/examples/cron.mdx @@ -14,8 +14,6 @@ import { TabItem, Tabs, TypeScriptExample, WranglerConfig } from "~/components"; To launch a container on a schedule, you can use a Workers [Cron Trigger](/workers/configuration/cron-triggers/). -For a full example, see the [Cron Container Template](https://github.com/mikenomitch/cron-container/tree/main). - Use a cron expression in your Wrangler config to specify the schedule: @@ -167,5 +165,7 @@ export default { ``` +For a full Container class example, see the [Cron Container Template](https://github.com/mikenomitch/cron-container/tree/main). + diff --git a/src/content/docs/containers/examples/websocket.mdx b/src/content/docs/containers/examples/websocket.mdx index 0e89a385c9a..71d3619472b 100644 --- a/src/content/docs/containers/examples/websocket.mdx +++ b/src/content/docs/containers/examples/websocket.mdx @@ -109,8 +109,9 @@ export default { ``` +View a full example in the [Container class repository](https://github.com/cloudflare/containers/tree/main/examples/websocket). + -View a full example in the [Container class repository](https://github.com/cloudflare/containers/tree/main/examples/websocket). {/* TODO: Add more advanced examples - like kicking off a WS request then passing messages to container from the WS */} From fe3320bc9b57cfe38b77863fcf5648af196c1b0b Mon Sep 17 00:00:00 2001 From: Thomas Gauvin Date: Tue, 29 Sep 2026 17:24:37 -0400 Subject: [PATCH 11/16] [Containers] Use Durable Object exports in examples --- .../containers/examples/container-backend.mdx | 16 ++++++------- src/content/docs/containers/examples/cron.mdx | 23 +++++++++++-------- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/src/content/docs/containers/examples/container-backend.mdx b/src/content/docs/containers/examples/container-backend.mdx index 7d9d5ea9aac..3062758c36c 100644 --- a/src/content/docs/containers/examples/container-backend.mdx +++ b/src/content/docs/containers/examples/container-backend.mdx @@ -54,14 +54,12 @@ but you can select from one of many frontend frameworks. See our [Workers framew } ] }, - "migrations": [ - { - "new_sqlite_classes": [ - "Backend" - ], - "tag": "v1" + "exports": { + "Backend": { + "type": "durable-object", + "storage": "sqlite" } - ] + } } ``` @@ -151,7 +149,7 @@ Because `container.start()` does not wait for readiness, this example polls `GET - + ```ts import { DurableObject } from "cloudflare:workers"; @@ -235,7 +233,7 @@ export default { - + ```ts import { Container, getRandom } from "@cloudflare/containers"; diff --git a/src/content/docs/containers/examples/cron.mdx b/src/content/docs/containers/examples/cron.mdx index a8c477ab40a..0758e1976fc 100644 --- a/src/content/docs/containers/examples/cron.mdx +++ b/src/content/docs/containers/examples/cron.mdx @@ -45,12 +45,12 @@ Use a cron expression in your Wrangler config to specify the schedule: } ] }, - "migrations": [ - { - "new_sqlite_classes": ["CronContainer"], - "tag": "v1" + "exports": { + "CronContainer": { + "type": "durable-object", + "storage": "sqlite" } - ] + } } ``` @@ -122,8 +122,10 @@ export default { return new Response("This Worker runs a scheduled Container task."); }, - async scheduled(_controller: ScheduledController, env: Env): Promise { - await env.CRON_CONTAINER.getByName("cron").run(new Date().toISOString()); + async scheduled(controller: ScheduledController, env: Env): Promise { + await env.CRON_CONTAINER + .getByName("cron") + .run(new Date(controller.scheduledTime).toISOString()); }, }; ``` @@ -153,11 +155,14 @@ export default { return new Response("This Worker runs a cron job to execute a container on a schedule."); }, - async scheduled(_controller: ScheduledController, env: { CRON_CONTAINER: DurableObjectNamespace }) { + async scheduled( + controller: ScheduledController, + env: { CRON_CONTAINER: DurableObjectNamespace }, + ): Promise { const container = getContainer(env.CRON_CONTAINER); await container.start({ envVars: { - MESSAGE: "Start Time: " + new Date().toISOString(), + MESSAGE: `Start Time: ${new Date(controller.scheduledTime).toISOString()}`, }, }); }, From bab46d3eb3e7c15701d4ba4773c3109c0aa613d9 Mon Sep 17 00:00:00 2001 From: Thomas Gauvin Date: Tue, 29 Sep 2026 17:28:01 -0400 Subject: [PATCH 12/16] [Containers] Clarify status hook health check --- src/content/docs/containers/examples/status-hooks.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/docs/containers/examples/status-hooks.mdx b/src/content/docs/containers/examples/status-hooks.mdx index 81e7978209b..de601966d54 100644 --- a/src/content/docs/containers/examples/status-hooks.mdx +++ b/src/content/docs/containers/examples/status-hooks.mdx @@ -15,7 +15,7 @@ import { TabItem, Tabs, TypeScriptExample } from "~/components"; Use `monitor()` with the Durable Object Container API to run code after the Container exits or errors. The `Container` class adds named lifecycle hooks and an inactivity callback. -Because `container.start()` does not wait for readiness, this example polls `GET /health` before forwarding requests. +The direct API example requires the Container to expose `GET /health` on port `4000`. The endpoint must return a successful response when the application is ready. Because `container.start()` does not wait for readiness, the Worker polls this endpoint before forwarding requests. From 59a00a8ce0b26c34370f4569aa3a650e4f1dfb62 Mon Sep 17 00:00:00 2001 From: Thomas Gauvin <35609369+thomasgauvin@users.noreply.github.com> Date: Tue, 29 Sep 2026 17:33:40 -0400 Subject: [PATCH 13/16] Update src/content/docs/containers/examples/cron.mdx Co-authored-by: Thomas Lefebvre --- src/content/docs/containers/examples/cron.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/docs/containers/examples/cron.mdx b/src/content/docs/containers/examples/cron.mdx index 0758e1976fc..3ba5b4a8389 100644 --- a/src/content/docs/containers/examples/cron.mdx +++ b/src/content/docs/containers/examples/cron.mdx @@ -56,7 +56,7 @@ Use a cron expression in your Wrangler config to specify the schedule: -Then call the Container from the `scheduled()` handler in the Worker. Because `container.start()` does not wait for readiness, this example polls `GET /health` before sending `POST /run` to start the scheduled task. +Call the Container from the Worker's `scheduled()` handler. The container image runs the task on startup and exits when finished. Await `monitor()` to observe completion or failure. From 3111a8c38331447db2b3ab2be41016ce008ac95a Mon Sep 17 00:00:00 2001 From: Thomas Gauvin <35609369+thomasgauvin@users.noreply.github.com> Date: Tue, 29 Sep 2026 17:33:52 -0400 Subject: [PATCH 14/16] Update src/content/docs/containers/examples/status-hooks.mdx Co-authored-by: Thomas Lefebvre --- src/content/docs/containers/examples/status-hooks.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/docs/containers/examples/status-hooks.mdx b/src/content/docs/containers/examples/status-hooks.mdx index de601966d54..27179779ded 100644 --- a/src/content/docs/containers/examples/status-hooks.mdx +++ b/src/content/docs/containers/examples/status-hooks.mdx @@ -125,4 +125,4 @@ export class MyContainer extends Container { -The `monitor()` promise in the direct API does not include an exit code or stop reason. The `setInactivityTimeout()` method does not invoke a callback when the timeout expires. Use the [`Container` class lifecycle hooks](/containers/api/container-class/#lifecycle-hooks) when you need those events. +The `monitor()` promise resolves without a value when the container exits successfully. For nonzero exits, it rejects with an error containing the exit code. The `setInactivityTimeout()` method does not invoke a callback when the timeout expires. Use the [`Container` class lifecycle hooks](/containers/api/container-class/#lifecycle-hooks) for structured stop parameters and an inactivity callback. From 2ca8643dc38957f16433eb9568b54387ffd3e23b Mon Sep 17 00:00:00 2001 From: Thomas Gauvin Date: Tue, 29 Sep 2026 17:37:42 -0400 Subject: [PATCH 15/16] [Containers] Align example internet access --- .../containers/examples/container-backend.mdx | 3 +- src/content/docs/containers/examples/cron.mdx | 35 +++---------------- .../docs/containers/examples/stateless.mdx | 3 +- .../docs/containers/examples/status-hooks.mdx | 3 +- .../docs/containers/examples/websocket.mdx | 3 +- 5 files changed, 12 insertions(+), 35 deletions(-) diff --git a/src/content/docs/containers/examples/container-backend.mdx b/src/content/docs/containers/examples/container-backend.mdx index 3062758c36c..cf7def125f2 100644 --- a/src/content/docs/containers/examples/container-backend.mdx +++ b/src/content/docs/containers/examples/container-backend.mdx @@ -186,7 +186,7 @@ export class Backend extends DurableObject { const container = this.ctx.container!; await container.setInactivityTimeout(2 * 60 * 60 * 1000); if (!container.running) { - container.start(); + container.start({ enableInternet: false }); } this.ctx.waitUntil( container @@ -246,6 +246,7 @@ interface Env { export class Backend extends Container { defaultPort = 8080; // pass requests to port 8080 in the container + enableInternet = false; sleepAfter = "2h"; // only sleep a container if it hasn't gotten requests in 2 hours } diff --git a/src/content/docs/containers/examples/cron.mdx b/src/content/docs/containers/examples/cron.mdx index 3ba5b4a8389..4686c29a84f 100644 --- a/src/content/docs/containers/examples/cron.mdx +++ b/src/content/docs/containers/examples/cron.mdx @@ -81,39 +81,11 @@ export class CronContainer extends DurableObject { private async runOnce(startTime: string): Promise { const container = this.ctx.container!; - await container.setInactivityTimeout(10_000); - if (!container.running) { - container.start(); - } - - const port = container.getTcpPort(8080); - let lastError: unknown; - for (let attempt = 0; attempt < 100; attempt++) { - try { - const response = await port.fetch("http://container/health"); - if (!response.ok) { - throw new Error(`Health check returned ${response.status}`); - } - lastError = undefined; - break; - } catch (error) { - lastError = error; - await scheduler.wait(200); - } - } - if (lastError) { - throw lastError; - } - - const response = await port.fetch("http://container/run", { - method: "POST", - body: JSON.stringify({ startTime }), - headers: { "content-type": "application/json" }, - }); - if (!response.ok) { - throw new Error(`Container returned ${response.status}`); + console.log("Starting scheduled task:", startTime); + container.start({ enableInternet: true }); } + await container.monitor(); } } @@ -161,6 +133,7 @@ export default { ): Promise { const container = getContainer(env.CRON_CONTAINER); await container.start({ + enableInternet: true, envVars: { MESSAGE: `Start Time: ${new Date(controller.scheduledTime).toISOString()}`, }, diff --git a/src/content/docs/containers/examples/stateless.mdx b/src/content/docs/containers/examples/stateless.mdx index 285fc1815ca..f3e33ddf10c 100644 --- a/src/content/docs/containers/examples/stateless.mdx +++ b/src/content/docs/containers/examples/stateless.mdx @@ -55,7 +55,7 @@ export class Backend extends DurableObject { const container = this.ctx.container!; await container.setInactivityTimeout(2 * 60 * 60 * 1000); if (!container.running) { - container.start(); + container.start({ enableInternet: false }); } const port = container.getTcpPort(8080); @@ -102,6 +102,7 @@ interface Env { export class Backend extends Container { defaultPort = 8080; + enableInternet = false; sleepAfter = "2h"; } diff --git a/src/content/docs/containers/examples/status-hooks.mdx b/src/content/docs/containers/examples/status-hooks.mdx index 27179779ded..f49eb87e0ca 100644 --- a/src/content/docs/containers/examples/status-hooks.mdx +++ b/src/content/docs/containers/examples/status-hooks.mdx @@ -52,7 +52,7 @@ export class MyContainer extends DurableObject { const container = this.ctx.container!; await container.setInactivityTimeout(5 * 60 * 1000); if (!container.running) { - container.start(); + container.start({ enableInternet: false }); } this.ctx.waitUntil( @@ -94,6 +94,7 @@ import { Container, type StopParams } from "@cloudflare/containers"; export class MyContainer extends Container { defaultPort = 4000; + enableInternet = false; sleepAfter = "5m"; override onStart() { diff --git a/src/content/docs/containers/examples/websocket.mdx b/src/content/docs/containers/examples/websocket.mdx index 71d3619472b..7f9e280a40f 100644 --- a/src/content/docs/containers/examples/websocket.mdx +++ b/src/content/docs/containers/examples/websocket.mdx @@ -53,7 +53,7 @@ export class MyContainer extends DurableObject { const container = this.ctx.container!; await container.setInactivityTimeout(2 * 60 * 1000); if (!container.running) { - container.start(); + container.start({ enableInternet: false }); } const port = container.getTcpPort(8080); @@ -97,6 +97,7 @@ interface Env { export class MyContainer extends Container { defaultPort = 8080; + enableInternet = false; sleepAfter = "2m"; } From fd515c1133a32d03764dc636a1411484d5c978b1 Mon Sep 17 00:00:00 2001 From: Thomas Gauvin Date: Tue, 29 Sep 2026 17:45:40 -0400 Subject: [PATCH 16/16] [Containers] Defer explicit internet access settings --- src/content/docs/containers/examples/container-backend.mdx | 3 +-- src/content/docs/containers/examples/cron.mdx | 3 +-- src/content/docs/containers/examples/stateless.mdx | 3 +-- src/content/docs/containers/examples/status-hooks.mdx | 3 +-- src/content/docs/containers/examples/websocket.mdx | 3 +-- 5 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/content/docs/containers/examples/container-backend.mdx b/src/content/docs/containers/examples/container-backend.mdx index cf7def125f2..3062758c36c 100644 --- a/src/content/docs/containers/examples/container-backend.mdx +++ b/src/content/docs/containers/examples/container-backend.mdx @@ -186,7 +186,7 @@ export class Backend extends DurableObject { const container = this.ctx.container!; await container.setInactivityTimeout(2 * 60 * 60 * 1000); if (!container.running) { - container.start({ enableInternet: false }); + container.start(); } this.ctx.waitUntil( container @@ -246,7 +246,6 @@ interface Env { export class Backend extends Container { defaultPort = 8080; // pass requests to port 8080 in the container - enableInternet = false; sleepAfter = "2h"; // only sleep a container if it hasn't gotten requests in 2 hours } diff --git a/src/content/docs/containers/examples/cron.mdx b/src/content/docs/containers/examples/cron.mdx index 4686c29a84f..61567becda1 100644 --- a/src/content/docs/containers/examples/cron.mdx +++ b/src/content/docs/containers/examples/cron.mdx @@ -83,7 +83,7 @@ export class CronContainer extends DurableObject { const container = this.ctx.container!; if (!container.running) { console.log("Starting scheduled task:", startTime); - container.start({ enableInternet: true }); + container.start(); } await container.monitor(); } @@ -133,7 +133,6 @@ export default { ): Promise { const container = getContainer(env.CRON_CONTAINER); await container.start({ - enableInternet: true, envVars: { MESSAGE: `Start Time: ${new Date(controller.scheduledTime).toISOString()}`, }, diff --git a/src/content/docs/containers/examples/stateless.mdx b/src/content/docs/containers/examples/stateless.mdx index f3e33ddf10c..285fc1815ca 100644 --- a/src/content/docs/containers/examples/stateless.mdx +++ b/src/content/docs/containers/examples/stateless.mdx @@ -55,7 +55,7 @@ export class Backend extends DurableObject { const container = this.ctx.container!; await container.setInactivityTimeout(2 * 60 * 60 * 1000); if (!container.running) { - container.start({ enableInternet: false }); + container.start(); } const port = container.getTcpPort(8080); @@ -102,7 +102,6 @@ interface Env { export class Backend extends Container { defaultPort = 8080; - enableInternet = false; sleepAfter = "2h"; } diff --git a/src/content/docs/containers/examples/status-hooks.mdx b/src/content/docs/containers/examples/status-hooks.mdx index f49eb87e0ca..27179779ded 100644 --- a/src/content/docs/containers/examples/status-hooks.mdx +++ b/src/content/docs/containers/examples/status-hooks.mdx @@ -52,7 +52,7 @@ export class MyContainer extends DurableObject { const container = this.ctx.container!; await container.setInactivityTimeout(5 * 60 * 1000); if (!container.running) { - container.start({ enableInternet: false }); + container.start(); } this.ctx.waitUntil( @@ -94,7 +94,6 @@ import { Container, type StopParams } from "@cloudflare/containers"; export class MyContainer extends Container { defaultPort = 4000; - enableInternet = false; sleepAfter = "5m"; override onStart() { diff --git a/src/content/docs/containers/examples/websocket.mdx b/src/content/docs/containers/examples/websocket.mdx index 7f9e280a40f..71d3619472b 100644 --- a/src/content/docs/containers/examples/websocket.mdx +++ b/src/content/docs/containers/examples/websocket.mdx @@ -53,7 +53,7 @@ export class MyContainer extends DurableObject { const container = this.ctx.container!; await container.setInactivityTimeout(2 * 60 * 1000); if (!container.running) { - container.start({ enableInternet: false }); + container.start(); } const port = container.getTcpPort(8080); @@ -97,7 +97,6 @@ interface Env { export class MyContainer extends Container { defaultPort = 8080; - enableInternet = false; sleepAfter = "2m"; }