Skip to content

Stateless Instances

Run multiple instances across Cloudflare's network

Last updated View as MarkdownAgent setup

To proxy requests across a fixed number of Container instances, select an instance name and forward the request through its Durable Object.

src/index.jsjs
import { DurableObject } from "cloudflare:workers";

const INSTANCE_COUNT = 3;

export class Backend extends DurableObject {
	constructor(ctx, env) {
		super(ctx, env);

		ctx.blockConcurrencyWhile(async () => {
			const container = ctx.container;
			await container.setInactivityTimeout(2 * 60 * 60 * 1000);

			if (!container.running) {
				container.start();
			}

			const port = container.getTcpPort(8080);
			let lastError;
			for (let attempt = 0; attempt < 50; attempt++) {
				try {
					await port.fetch("http://container/");
					return;
				} catch (error) {
					lastError = error;
					await scheduler.wait(100);
				}
			}
			throw lastError;
		});
	}

	fetch(request) {
		return this.ctx.container.getTcpPort(8080).fetch(request);
	}
}

export default {
	async fetch(request, env) {
		const index = Math.floor(Math.random() * INSTANCE_COUNT);
		return env.BACKEND.getByName(`instance-${index}`).fetch(request);
	},
};
src/index.tsts
import { DurableObject } from "cloudflare:workers";

const INSTANCE_COUNT = 3;

interface Env {
	BACKEND: DurableObjectNamespace<Backend>;
}

export class Backend extends DurableObject<Env> {
	constructor(ctx: DurableObjectState, env: Env) {
		super(ctx, env);

		ctx.blockConcurrencyWhile(async () => {
			const container = 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 < 50; attempt++) {
				try {
					await port.fetch("http://container/");
					return;
				} catch (error) {
					lastError = error;
					await scheduler.wait(100);
				}
			}
			throw lastError;
		});
	}

	fetch(request: Request): Promise<Response> {
		return this.ctx.container!.getTcpPort(8080).fetch(request);
	}
}

export default {
	async fetch(request: Request, env: Env): Promise<Response> {
		const index = Math.floor(Math.random() * INSTANCE_COUNT);
		return env.BACKEND.getByName(`instance-${index}`).fetch(request);
	},
};
import { Container, getRandom } from "@cloudflare/containers";

const INSTANCE_COUNT = 3;

class Backend extends Container {
	defaultPort = 8080;
	sleepAfter = "2h";
}

export default {
	async fetch(request: Request, env: Env): Promise<Response> {
		const containerInstance = await getRandom(env.BACKEND, INSTANCE_COUNT);
		return containerInstance.fetch(request);
	},
};

Was this helpful?