UNPKG

@cadence-mq/driver-memory

Version:
105 lines (102 loc) 3.6 kB
import { createErrorFactory, createJobNotFoundError } from "@cadence-mq/core"; //#region src/errors.ts const createJobWithSameIdExistsError = createErrorFactory({ code: "jobs.unique-id-constraint-violation", message: "A job with the same id already exists" }); //#endregion //#region src/driver.ts function getNextJob({ jobsRegistry, processingTimeoutMs, now = /* @__PURE__ */ new Date() }) { let nextJob = null; const isJobSelectable = (job) => job.status === "pending" || job.status === "processing" && job.startedAt && job.startedAt.getTime() + processingTimeoutMs < now.getTime(); const isJobScheduledEarlier = (job) => nextJob === null || job.scheduledAt < nextJob.scheduledAt; for (const job of jobsRegistry.values()) if (isJobSelectable(job) && isJobScheduledEarlier(job)) nextJob = job; return nextJob; } function createMemoryDriver() { const jobsRegistry = /* @__PURE__ */ new Map(); const pendingResolvers = []; let nextJobTimeout = null; const consumeNextJob = async ({ job }) => { const resolver = pendingResolvers.shift(); if (!resolver) return; resolver({ job }); }; const refreshConsumption = ({ processingTimeoutMs, getNow = () => /* @__PURE__ */ new Date() }) => { const now = getNow(); const nextJob = getNextJob({ jobsRegistry, processingTimeoutMs, now }); const nextJobProcessingExpiresAt = nextJob?.startedAt ? new Date(nextJob.startedAt.getTime() + processingTimeoutMs) : void 0; if (nextJobTimeout) clearTimeout(nextJobTimeout); if (!nextJob) return; const availableAt = nextJob.status === "processing" ? nextJobProcessingExpiresAt : nextJob.scheduledAt; const deltaMs = availableAt.getTime() - now.getTime(); if (deltaMs <= 0) { consumeNextJob({ job: nextJob }); return; } nextJobTimeout = setTimeout(() => { refreshConsumption({ processingTimeoutMs, getNow }); }, deltaMs); }; return { getNextJobAndMarkAsProcessing: async ({ now = /* @__PURE__ */ new Date() }) => { const { promise, resolve } = Promise.withResolvers(); pendingResolvers.push(resolve); refreshConsumption({ processingTimeoutMs: 10 * 60 * 1e3 }); const { job } = await promise; jobsRegistry.set(job.id, { ...job, status: "processing", startedAt: now }); return { job }; }, saveJob: async ({ job }) => { if (jobsRegistry.has(job.id)) throw createJobWithSameIdExistsError(); jobsRegistry.set(job.id, job); refreshConsumption({ processingTimeoutMs: 10 * 60 * 1e3 }); }, getJob: async ({ jobId }) => { const job = jobsRegistry.get(jobId); if (!job) return { job: null }; return { job: { result: void 0, error: void 0, startedAt: void 0, completedAt: void 0, cron: void 0, ...job } }; }, getJobCount: async ({ filter } = {}) => { if (!filter) return { count: jobsRegistry.size }; const filterEntries = Object.entries(filter); const isJobMatchingFilter = (job) => filterEntries.every(([key, value]) => job[key] === value); const filteredJobs = Array.from(jobsRegistry.values()).filter(isJobMatchingFilter); return { count: filteredJobs.length }; }, updateJob: async ({ jobId, values }) => { const existingJob = jobsRegistry.get(jobId); if (!existingJob) throw createJobNotFoundError(); jobsRegistry.set(jobId, { ...existingJob, ...values }); }, deleteJob: async ({ jobId }) => { const existingJob = jobsRegistry.get(jobId); if (!existingJob) throw createJobNotFoundError(); jobsRegistry.delete(jobId); } }; } //#endregion export { createMemoryDriver }; //# sourceMappingURL=index.js.map