1import * as Cloudflare from "alchemy/Cloudflare";
2import * as Effect from "effect/Effect";
3import * as Schedule from "effect/Schedule";
4import * as HttpClientRequest from "effect/http/HttpClientRequest";
5import { RemoteContainer } from "./remote-container.ts";
6
7/**
8 * Durable Object backing one remote (non-effectful) container instance.
9 * `boot()` blocks until the container's HTTP server answers on its TCP port.
10 * NOTE: the authoritative cold-start clock runs in the Worker AROUND the whole
11 * DO call — the container layer eagerly starts the container during DO
12 * construction, so a clock started here would miss part of the start.
13 */
14export class RemoteObject extends Cloudflare.DurableObject<RemoteObject>()(
15 "BenchRemoteObject",
16 Effect.gen(function* () {
17 const container = yield* RemoteContainer;
18
19 return Effect.gen(function* () {
20 const { fetch } = yield* container.getTcpPort(8080);
21
22 return {
23 boot: () =>
24 Effect.gen(function* () {
25 const start = yield* Effect.sync(() => Date.now());
26 yield* fetch(HttpClientRequest.get("http://container/")).pipe(
27 Effect.flatMap((r) => r.text),
28 Effect.retry({
29 schedule: Schedule.min([Schedule.exponential("1 second"), Schedule.spaced("5 seconds")]),
30 times: 40,
31 }),
32 );
33 const readyMs = (yield* Effect.sync(() => Date.now())) - start;
34 return { readyMs };
35 }),
36 shutdown: () => container.destroy().pipe(Effect.ignore),
37 };
38 });
39 }).pipe(
40 Effect.provide(
41 Cloudflare.Containers.layer(RemoteContainer, {
42 enableInternet: true,
43 }),
44 ),
45 ),
46) {}