1import * as AWS from "alchemy/AWS";
2import * as Kubernetes from "alchemy/Kubernetes";
3import * as Effect from "effect/Effect";
4import { EntriesTable, GuestbookCluster, GuestbookNamespace } from "./infra.ts";
5
6const seedEntries = [
7 { id: "ada", message: "First computers, now clusters." },
8 {
9 id: "grace",
10 message:
11 "A cluster in port is safe, but that is not what clusters are for.",
12 },
13 { id: "linus", message: "Talk is cheap. Show me the manifest." },
14];
15
16/**
17 * A one-shot `Kubernetes.Job` in the INLINE EFFECT form: props + an init Effect
18 * whose impl returns `{ run }` — a one-shot entry that executes to
19 * completion inside the pod, after which the process exits (the Kubernetes
20 * analog of `AWS.ECS.Task`).
21 *
22 * The Effect program is bundled into a generated image
23 * (`main: import.meta.url` names this module as the entrypoint). The
24 * `AWS.DynamoDB.PutItem` binding injects the table's name into the pod and
25 * grants `dynamodb:PutItem` on the generated pod-identity role.
26 *
27 * Applying the batch/v1 Job runs it: the seed executes once on deploy.
28 * Adding `schedule: "0 3 * * *"` to the props would synthesize a CronJob
29 * instead.
30 */
31export default Kubernetes.Job(
32 "SeedJob",
33 // Props are themselves an Effect so they can reference shared resources.
34 Effect.gen(function* () {
35 const cluster = yield* GuestbookCluster;
36 const ns = yield* GuestbookNamespace;
37 return {
38 cluster,
39 main: import.meta.url,
40 // Deploy after the namespace exists (see src/infra.ts).
41 namespace: ns.name,
42 backoffLimit: 2,
43 };
44 }),
45 Effect.gen(function* () {
46 const table = yield* EntriesTable;
47 const putItem = yield* AWS.DynamoDB.PutItem(table);
48
49 return {
50 // One-shot entry: seed the table, log, exit 0.
51 run: Effect.gen(function* () {
52 yield* Effect.forEach(
53 seedEntries,
54 (entry) =>
55 putItem({
56 Item: {
57 pk: { S: `entry#${entry.id}` },
58 author: { S: entry.id },
59 message: { S: entry.message },
60 },
61 }),
62 { discard: true },
63 );
64 yield* Effect.log(`seeded ${seedEntries.length} guestbook entries`);
65 }).pipe(Effect.orDie),
66 };
67 }).pipe(Effect.provide(AWS.DynamoDB.PutItemHttp)),
68);