| 1 | import * as AWS from "alchemy/AWS"; |
| 2 | import * as Effect from "effect/Effect"; |
| 3 | import { OrdersTable } from "./infra.ts"; |
| 4 | |
| 5 | const seedOrders = [ |
| 6 | { id: "1001", customer: "ada", total: 4250 }, |
| 7 | { id: "1002", customer: "grace", total: 1799 }, |
| 8 | { id: "1003", customer: "linus", total: 999 }, |
| 9 | ]; |
| 10 | |
| 11 | /** |
| 12 | * A one-shot `AWS.ECS.Task` in the INLINE EFFECT form: props + an init |
| 13 | * Effect whose impl returns `{ run }` — a one-shot entry that executes to |
| 14 | * completion when the container starts, after which the container exits. |
| 15 | * |
| 16 | * The Effect program is bundled into a generated image `FROM image` |
| 17 | * (`main: import.meta.url` names this module as the entrypoint). The |
| 18 | * `AWS.DynamoDB.PutItem` binding injects the table's name into the |
| 19 | * container environment and grants `dynamodb:PutItem` on the task role. |
| 20 | * |
| 21 | * Nothing runs this task on deploy — it is the target of the |
| 22 | * `AWS.ECS.RunTask(cluster, SeedTask)` binding the `Api` service exposes at |
| 23 | * `POST /api/seed`. A task definition is cluster-independent (mirroring |
| 24 | * `AWS::ECS::TaskDefinition`), so the launch cluster is declared where the |
| 25 | * launch is bound, not here. |
| 26 | */ |
| 27 | export default AWS.ECS.Task( |
| 28 | "SeedTask", |
| 29 | { |
| 30 | main: import.meta.url, |
| 31 | // Docker Hub's `oven/bun`; the public.ecr.aws default mirror |
| 32 | // rate-limits anonymous pulls during local builds. |
| 33 | image: "oven/bun:1", |
| 34 | cpu: 256, |
| 35 | memory: 512, |
| 36 | // Build/run on ARM64 so an image built on an Apple Silicon host matches |
| 37 | // the Fargate runtime architecture (Graviton). |
| 38 | runtimePlatform: { |
| 39 | cpuArchitecture: "ARM64", |
| 40 | operatingSystemFamily: "LINUX", |
| 41 | }, |
| 42 | }, |
| 43 | Effect.gen(function* () { |
| 44 | const table = yield* OrdersTable; |
| 45 | const putItem = yield* AWS.DynamoDB.PutItem(table); |
| 46 | |
| 47 | return { |
| 48 | // One-shot entry: seed the table, log, exit 0. |
| 49 | run: Effect.gen(function* () { |
| 50 | yield* Effect.forEach( |
| 51 | seedOrders, |
| 52 | (order) => |
| 53 | putItem({ |
| 54 | Item: { |
| 55 | pk: { S: `order#${order.id}` }, |
| 56 | customer: { S: order.customer }, |
| 57 | total: { N: String(order.total) }, |
| 58 | }, |
| 59 | }), |
| 60 | { discard: true }, |
| 61 | ); |
| 62 | yield* Effect.log(`seeded ${seedOrders.length} orders`); |
| 63 | }).pipe(Effect.orDie), |
| 64 | }; |
| 65 | }).pipe(Effect.provide(AWS.DynamoDB.PutItemHttp)), |
| 66 | ); |