UNPKG

alepha

Version:

Easy-to-use modern TypeScript framework for building many kind of applications.

110 lines (102 loc) 5.07 kB
import { $module } from "alepha"; import { AlephaBackground } from "alepha/background"; import type { DateTime } from "alepha/datetime"; import { AlephaLock } from "alepha/lock"; import { AlephaQueue } from "alepha/queue"; import { AlephaScheduler } from "alepha/scheduler"; import { AdminJobController } from "./controllers/AdminJobController.ts"; import { $job } from "./primitives/$job.ts"; import { DirectJobDispatcher } from "./providers/DirectJobDispatcher.ts"; import { JobProvider } from "./providers/JobProvider.ts"; import { JobQueueProvider } from "./providers/JobQueueProvider.ts"; import { JobService } from "./services/JobService.ts"; // ----------------------------------------------------------------------------------------------------------------- export * from "./controllers/AdminJobController.ts"; export * from "./entities/jobExecutionEntity.ts"; export * from "./primitives/$job.ts"; export * from "./providers/DirectJobDispatcher.ts"; export * from "./providers/JobDispatcher.ts"; export * from "./providers/JobProvider.ts"; export * from "./providers/JobQueueProvider.ts"; export * from "./schemas/jobConfigAtom.ts"; export * from "./schemas/jobExecutionQuerySchema.ts"; export * from "./schemas/jobExecutionResourceSchema.ts"; export * from "./schemas/jobRegistrationSchema.ts"; export * from "./schemas/triggerJobSchema.ts"; export * from "./services/JobService.ts"; // ----------------------------------------------------------------------------------------------------------------- declare module "alepha" { interface Hooks { "job:begin": { name: string; now: DateTime; executionId: string }; "job:success": { name: string; executionId: string }; "job:error": { name: string; error: Error; executionId: string }; "job:cancel": { name: string; executionId: string }; "job:end": { name: string; executionId: string }; } } // ----------------------------------------------------------------------------------------------------------------- /** * Job execution framework — cron and durable queue work with a single primitive. * * A `$job` is either **cron-only** (declares `cron`) or **payload-only** (declares `schema`). * * **Three runtime modes:** * * - **cron** — fires on a schedule. Cron-mode jobs are protected by a * distributed lock by default (`lock: true`), so multi-replica Docker * deployments only run the handler once per tick. Override with * `lock: false` if you genuinely want every replica to fire. * - **queue** — push-driven, dispatched through the queue infrastructure * (`AlephaQueue`, e.g. Cloudflare Queues, Redis). Real-time delivery, * ideal for high-volume systems. Requires `AlephaApiJobsQueue`. * - **direct** — push-driven, processed in-process right after the caller * awaits the push. The DB outbox row is the durability guarantee — if * the process dies, the reconciliation sweep re-dispatches. Default * when `AlephaApiJobsQueue` is *not* loaded. Best for cheap deployments * (Cloudflare Workers, single-instance Node) where standing up a queue * is overkill. * * **Retries** are sweep-driven across all modes (no exponential backoff). * Granularity is bounded by `sweepCron` (default 15 min). The first retry * may land anywhere from a few seconds to ~15 min later depending on when * the next sweep tick fires. Cron jobs that declare `retry` go through * the same sweep path — a transient failure no longer means waiting for * the next cron tick (useful for once-daily jobs). * * **Runtime support for cron triggers** * * - **Long-running Node / Docker** — `CronProvider` runs an in-process * timer loop. Multi-replica deployments serialize ticks via the cron * lock (see `$job.lock`). * - **Cloudflare Workers** — the build emits cron expressions into * `wrangler.jsonc`; Cloudflare invokes the worker on schedule and the * `cloudflare:scheduled` hook routes the event to the matching jobs. * - **Vercel** — the build emits cron entries into * `.vercel/output/config.json` mapped to `/_alepha/cron/:name`; the * serverless handler emits `serverless:cron` and `CronProvider` runs * the matching job. Set `CRON_SECRET` to require authenticated calls. * * @module alepha.api.jobs */ export const AlephaApiJobs = $module({ name: "alepha.api.jobs", primitives: [$job], imports: [AlephaScheduler, AlephaLock, AlephaBackground], services: [JobProvider, JobService, AdminJobController, DirectJobDispatcher], }); /** * Queue support for `$job`. Import alongside {@link AlephaApiJobs} when your * app declares queue-mode jobs (any `$job` with a `schema`) and you want a * real queue (e.g. Cloudflare Queues, Redis) instead of in-process direct * execution. * * Adds `JobQueueProvider` to the container. `JobProvider` detects its * presence at start-up and routes dispatches through it. * * @module alepha.api.jobs.queue */ export const AlephaApiJobsQueue = $module({ name: "alepha.api.jobs.queue", imports: [AlephaApiJobs, AlephaQueue], services: [JobQueueProvider], });