import type { Clock } from "../clock"; import type { Db } from "../db/client"; import { withPlayerLock } from "../game/lock"; import { resolveArrivedDispatches } from "../game/resolve"; import { cleanupExpiredContracts } from "./cleanup"; import type { JobDefinition } from "./queue"; export const RESOLVE_ARRIVALS_JOB = "resolve-arrivals"; export const CLEANUP_CONTRACTS_JOB = "cleanup-expired-contracts"; export interface JobContext { db: Db; clock: Clock; } /** * Resolves a player's arrived dispatches, exactly like lazy resolution on read * (Step 7.2). Scheduled for each dispatch's arrival; does nothing if a request * already resolved it. */ export async function resolveArrivalsJob(ctx: JobContext, data: Record) { const playerId = data.playerId; if (typeof playerId !== "string") throw new Error("resolve-arrivals job needs a playerId"); await withPlayerLock(ctx.db, playerId, (tx) => resolveArrivedDispatches(tx, playerId, ctx.clock()), ); } /** Every background job the app runs. */ export function appJobs(ctx: JobContext): JobDefinition[] { return [ { name: RESOLVE_ARRIVALS_JOB, handler: (data) => resolveArrivalsJob(ctx, data) }, { name: CLEANUP_CONTRACTS_JOB, // Hourly, on the hour (UTC). cron: "0 * * * *", handler: async () => { await cleanupExpiredContracts(ctx.db, ctx.clock()); }, }, ]; }