alepha
Version:
Easy-to-use modern TypeScript framework for building many kind of applications.
110 lines (102 loc) • 5.07 kB
text/typescript
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],
});