1/// <reference types="@cloudflare/workers-types" />
2
3import { Container, getContainer } from "@cloudflare/containers";
4
5interface Env {
6 BENCH_CONTAINER: DurableObjectNamespace<BenchContainer>;
7 CRASH_CONTAINER: DurableObjectNamespace<CrashContainer>;
8}
9
10/**
11 * Plain `@cloudflare/containers` container — no Alchemy involved. The DO proxies
12 * `fetch` to the Bun HTTP server on port 8080; the first `fetch` blocks through
13 * the container's cold start (the helper calls `startAndWaitForPorts`
14 * internally), so timing a single `fetch` measures start → reachable.
15 */
16export class BenchContainer extends Container<Env> {
17 defaultPort = 8080;
18 sleepAfter = "2m";
19}
20
21/**
22 * Crash-loop control: its image exits immediately, so `fetch` can never reach
23 * it. Native surfaces the fatal crash from its monitor and returns a 5xx; we
24 * time how fast that happens to baseline Alchemy's fail-fast behaviour.
25 */
26export class CrashContainer extends Container<Env> {
27 defaultPort = 8080;
28 sleepAfter = "2m";
29}
30
31export default {
32 async fetch(request, env): Promise<Response> {
33 const url = new URL(request.url);
34
35 // `/start?name=X` boots the container instance named `X` and reports the
36 // cold-start-to-reachable latency measured inside the Worker.
37 if (url.pathname === "/start") {
38 const name = url.searchParams.get("name") ?? "default";
39 const container = getContainer(env.BENCH_CONTAINER, name);
40 const start = Date.now();
41 try {
42 const res = await container.fetch(new Request("http://container/"));
43 await res.text();
44 return Response.json({ ms: Date.now() - start, status: res.status });
45 } catch (err) {
46 return Response.json(
47 { error: String(err), ms: Date.now() - start },
48 { status: 500 },
49 );
50 }
51 }
52
53 // `/crashloop?name=X` attempts to reach a container that crash-loops and
54 // reports how long until the failure surfaces (native returns a 5xx). `ok`
55 // is true only on a 2xx — always false here.
56 if (url.pathname === "/crashloop") {
57 const name = url.searchParams.get("name") ?? "default";
58 const container = getContainer(env.CRASH_CONTAINER, name);
59 const start = Date.now();
60 try {
61 const res = await container.fetch(new Request("http://container/"));
62 await res.text();
63 return Response.json({ ms: Date.now() - start, ok: res.ok });
64 } catch (err) {
65 return Response.json({
66 ms: Date.now() - start,
67 ok: false,
68 error: String(err),
69 });
70 }
71 }
72
73 return new Response("ok");
74 },
75} satisfies ExportedHandler<Env>;