| 1 | import * as ECS from "@/AWS/ECS"; |
| 2 | import * as Lambda from "@/AWS/Lambda"; |
| 3 | import * as Duration from "effect/Duration"; |
| 4 | import * as Effect from "effect/Effect"; |
| 5 | import * as HttpServerResponse from "effect/http/HttpServerResponse"; |
| 6 | import path from "pathe"; |
| 7 | |
| 8 | const main = path.resolve(import.meta.dirname, "nested-ecs-lambda.ts"); |
| 9 | |
| 10 | // A nested Platform (ECS.Task) yielded DIRECTLY inside the Lambda's init |
| 11 | // program — the shape that used to OOM the Lambda sandbox at init (the ECS |
| 12 | // Bindings handler avoids it with `Resource.ref`). This exercises the |
| 13 | // nested-Platform ConfigProvider interceptor path in Platform.ts: the outer |
| 14 | // Lambda's intercepting ConfigProvider is the ambient provider while the |
| 15 | // nested Task's layer builds, and the fix ensures the host `get` reads |
| 16 | // `process.env` directly instead of recursing back through the interceptor. |
| 17 | // |
| 18 | // Honest external form: a pre-built busybox image (mirrored into ECR), no |
| 19 | // Effect program — we only need the Task to deploy and the Lambda sandbox |
| 20 | // to boot. |
| 21 | const NestedOneShotTask = ECS.Task("NestedReproOneShotTask", { |
| 22 | image: "busybox:stable", |
| 23 | command: ["sh", "-c", "echo alchemy-nested-repro-oneshot"], |
| 24 | cpu: 256, |
| 25 | memory: 512, |
| 26 | taskName: "alchemy-nested-repro-oneshot", |
| 27 | }); |
| 28 | |
| 29 | export class NestedEcsReproFunction extends Lambda.Function<Lambda.Function>()( |
| 30 | "NestedEcsReproFunction", |
| 31 | ) {} |
| 32 | |
| 33 | export default NestedEcsReproFunction.make( |
| 34 | { |
| 35 | main, |
| 36 | functionUrl: true, |
| 37 | timeout: Duration.seconds(30), |
| 38 | memorySize: 512, |
| 39 | }, |
| 40 | Effect.gen(function* () { |
| 41 | // Yielding the ECS Task (a Platform) directly inside the Lambda init is |
| 42 | // the exact nesting that OOMed the sandbox before the Platform.ts fix. |
| 43 | const task = yield* NestedOneShotTask; |
| 44 | const containerName = yield* task.containerName; |
| 45 | |
| 46 | return { |
| 47 | fetch: Effect.gen(function* () { |
| 48 | // If the sandbox init recursed/OOMed, this route would never serve. |
| 49 | return yield* HttpServerResponse.json({ |
| 50 | ok: true, |
| 51 | taskType: task.Type, |
| 52 | containerName, |
| 53 | }); |
| 54 | }), |
| 55 | }; |
| 56 | }), |
| 57 | ); |