UNPKG

alepha

Version:

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

82 lines (70 loc) 2.81 kB
import { type Static, z } from "alepha"; import { logEntrySchema } from "alepha/logger"; import { $entity, db } from "alepha/orm"; /** * Job execution record. * * Stores durable state for queue-mode jobs (outbox pattern) and error records * for cron-mode jobs. Successful executions are trimmed by the sweep to keep * the last N rows per job (configurable via `jobConfig.keepLastSuccess`). * * Status transitions: * - queue push → pending (or `scheduled` if `delay`/`scheduledAt` was given) * - worker claim → running * - success → ok (or row deleted, depending on `record` and `keepLastSuccess`) * - terminal failure → error * - retryable failure → scheduled (with scheduledAt = now; sweep picks it up) * - delay → scheduled (with scheduledAt = now + delay) * - sweep picks due ones → pending * - cancel → cancelled */ export const jobExecutionEntity = $entity({ name: "job_executions", schema: z.object({ id: db.primaryKey(z.uuid()), createdAt: db.createdAt(), updatedAt: db.updatedAt(), jobName: z.text(), key: z.text().nullable().optional(), /** * Owning tenant for this execution, when it was pushed in (or for) a tenant * context. Used to org-scope tenant-facing views — notably the notification * admin list, which is backed by this outbox. Nullable: cron / global / non- * tenant pushes carry none. Deliberately NOT `db.organization()`: the job * worker + sweep must see every org's rows, so this stays a plain, * non-auto-scoping column rather than an auto-filtered one. */ organizationId: z.uuid().nullable().optional(), status: db.default( z.enum(["pending", "running", "scheduled", "ok", "error", "cancelled"]), "pending", ), priority: db.default(z.integer().min(0).max(3), 2), attempt: db.default(z.integer(), 0), maxAttempts: db.default(z.integer(), 1), payload: z.record(z.text(), z.any()).optional(), scheduledAt: z.datetime().optional(), startedAt: z.datetime().optional(), completedAt: z.datetime().optional(), error: z.text().optional(), logs: z.array(logEntrySchema).optional(), triggeredBy: z.text().optional(), triggeredByName: z.text().optional(), cancelledBy: z.text().optional(), cancelledByName: z.text().optional(), }), indexes: [ { columns: ["jobName", "status", "scheduledAt"] }, { columns: ["jobName", "status", "createdAt"] }, { columns: ["jobName", "startedAt"] }, { columns: ["jobName", "key"], unique: true }, ], }); export type JobExecutionEntity = Static<typeof jobExecutionEntity.schema>; export type JobStatus = | "pending" | "running" | "scheduled" | "ok" | "error" | "cancelled";