1import * as GCP from "@/GCP";
2import * as Effect from "effect/Effect";
3import * as HttpServerResponse from "effect/http/HttpServerResponse";
4
5export const SCHEDULE_ID = "Heartbeat";
6export const SCHEDULE_BODY = "hello-scheduler";
7
8/** Marker object the consumer writes for one scheduled run. */
9export const markerFor = (jobName: string) => `markers/${jobName}.json`;
10
11/** Bucket the consumer records runs in. */
12export const Markers = GCP.Storage.Bucket("ScheduleMarkers", {
13 location: "US-CENTRAL1",
14 forceDestroy: true,
15});
16
17/**
18 * Effect-native Cloud Run service that consumes a (yearly, so never
19 * naturally firing during a test) Cloud Scheduler job and records each run
20 * as a marker object. Deployed from {@link ../ScheduleEventSource.test.ts}.
21 */
22export default class ScheduleService extends GCP.Function<ScheduleService>()(
23 "ScheduleService",
24 {
25 main: import.meta.url,
26 location: "us-central1",
27 },
28 Effect.gen(function* () {
29 const bucket = yield* Markers;
30 const putObject = yield* GCP.Storage.PutObject(bucket);
31
32 yield* GCP.CloudScheduler.consumeSchedule(
33 SCHEDULE_ID,
34 { schedule: "0 0 1 1 *", timeZone: "Etc/UTC", body: SCHEDULE_BODY },
35 (event) =>
36 putObject({
37 name: markerFor(event.jobName),
38 body: JSON.stringify(event),
39 }).pipe(Effect.asVoid, Effect.orDie),
40 );
41
42 return {
43 fetch: Effect.succeed(HttpServerResponse.text("ok")),
44 };
45 }).pipe(
46 Effect.provide(GCP.Run.ScheduleEventSource),
47 Effect.provide(GCP.Storage.PutObjectHttp),
48 ),
49) {}