1import * as AWS from "@/AWS";
2import { ServerHost } from "@/Server/Process.ts";
3import * as Effect from "effect/Effect";
4import * as Ref from "effect/Ref";
5import * as Schedule from "effect/Schedule";
6import { HttpServerRequest } from "effect/http/HttpServerRequest";
7import * as HttpServerResponse from "effect/http/HttpServerResponse";
8
9/**
10 * End-to-end fixture for the Effect-native `AWS.AppRunner.Service` form: an
11 * inline Effect HTTP program bundled + containerized + pushed to a managed
12 * ECR repository and deployed as an App Runner service.
13 *
14 * - `yield* ServerHost` + `host.run(...)` registers a background loop that
15 * increments a counter once a second.
16 * - the returned `{ fetch }` handler is served over HTTP by the container's
17 * Bun HTTP server on the App Runner-injected `PORT`. `/ticks` reports the
18 * counter so the test can prove the background loop actually runs inside
19 * the deployed service.
20 */
21export default class TestService extends AWS.AppRunner.Service<TestService>()(
22 "AppRunnerE2EService",
23 {
24 main: import.meta.filename,
25 serviceName: "alchemy-test-apprunner-e2e",
26 port: 3000,
27 instanceConfiguration: { cpu: "256", memory: "512" },
28 healthCheckConfiguration: { protocol: "HTTP", path: "/health" },
29 // Docker Hub's `oven/bun` image; the public.ecr.aws default mirror
30 // aggressively rate-limits anonymous pulls (429) during local builds.
31 docker: { base: "oven/bun:1" },
32 },
33 Effect.gen(function* () {
34 const host = yield* ServerHost;
35 const ticks = yield* Ref.make(0);
36
37 // Long-running background loop (the `host.run` pattern).
38 yield* host.run(
39 Ref.update(ticks, (n) => n + 1).pipe(
40 Effect.repeat(Schedule.spaced("1 second")),
41 Effect.asVoid,
42 ),
43 );
44
45 return {
46 fetch: Effect.gen(function* () {
47 const request = yield* HttpServerRequest;
48 const url = new URL(request.url, "http://service");
49 if (url.pathname === "/health") {
50 return yield* HttpServerResponse.json({ ok: true });
51 }
52 if (url.pathname === "/ticks") {
53 return yield* HttpServerResponse.json({
54 ticks: yield* Ref.get(ticks),
55 });
56 }
57 return HttpServerResponse.text("hello from app runner");
58 }),
59 };
60 }),
61) {}