1import { Task } from "@/AWS/ECS/Task.ts";
2import * as Dockerfile from "@/Docker/Dockerfile.ts";
3import * as Effect from "effect/Effect";
4import * as FileSystem from "effect/FileSystem";
5
6/**
7 * A one-shot `AWS.ECS.Task` whose ENVIRONMENT is inline Dockerfile content
8 * (`Dockerfile.inline`) composed with a bundled `main` program.
9 *
10 * The inline content carries its own `FROM` plus a `RUN` that bakes a marker
11 * file into an image layer; the bundled `{ run }` program then reads that
12 * file back at container runtime and exits non-zero if it is missing or
13 * wrong. A Fargate exit code of 0 therefore proves BOTH halves of the
14 * composition: the inline content replaced the generated `FROM` preamble
15 * (the `RUN` executed during the build), and the Effect bundle was layered
16 * on top of that environment (the program ran inside it).
17 */
18export class InlineDockerfileTask extends Task<InlineDockerfileTask>()(
19 "EcsInlineDockerfileTask",
20) {}
21
22export default InlineDockerfileTask.make(
23 {
24 main: import.meta.filename,
25 dockerfile: Dockerfile.inline`
26FROM oven/bun:1
27RUN echo inline-env-artifact > /inline-artifact.txt
28`,
29 cpu: 256,
30 memory: 512,
31 // Build/run on ARM64 so an image built on an Apple Silicon host matches
32 // the Fargate runtime architecture (Graviton).
33 runtimePlatform: {
34 cpuArchitecture: "ARM64",
35 operatingSystemFamily: "LINUX",
36 },
37 taskName: "alchemy-test-ecs-inline-dockerfile",
38 },
39 Effect.gen(function* () {
40 const fs = yield* FileSystem.FileSystem;
41 return {
42 run: Effect.gen(function* () {
43 const artifact = yield* fs.readFileString("/inline-artifact.txt");
44 if (artifact.trim() !== "inline-env-artifact") {
45 return yield* Effect.die(
46 new Error(`unexpected artifact content: ${artifact}`),
47 );
48 }
49 yield* Effect.log("alchemy-inline-dockerfile-artifact-ok");
50 }).pipe(Effect.orDie),
51 };
52 }),
53);