@vielzeug/postmaster 3.0.0 → 3.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_json.cjs +1 -1
- package/dist/_json.cjs.map +1 -1
- package/dist/_json.js +1 -32
- package/dist/_json.js.map +1 -1
- package/dist/_store-utils.cjs +1 -1
- package/dist/_store-utils.cjs.map +1 -1
- package/dist/_store-utils.js +1 -13
- package/dist/_store-utils.js.map +1 -1
- package/dist/definitions.cjs +1 -1
- package/dist/definitions.cjs.map +1 -1
- package/dist/definitions.js +1 -32
- package/dist/definitions.js.map +1 -1
- package/dist/errors.cjs +1 -1
- package/dist/errors.cjs.map +1 -1
- package/dist/errors.js +1 -9
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -4
- package/dist/indexeddb.cjs +1 -1
- package/dist/indexeddb.cjs.map +1 -1
- package/dist/indexeddb.js +1 -175
- package/dist/indexeddb.js.map +1 -1
- package/dist/postmaster.cjs +1 -1
- package/dist/postmaster.cjs.map +1 -1
- package/dist/postmaster.d.ts.map +1 -1
- package/dist/postmaster.iife.js +1 -1
- package/dist/postmaster.iife.js.map +1 -1
- package/dist/postmaster.js +1 -1
- package/dist/postmaster.js.map +1 -1
- package/dist/store-ops.cjs +1 -1
- package/dist/store-ops.cjs.map +1 -1
- package/dist/store-ops.d.ts +3 -3
- package/dist/store-ops.d.ts.map +1 -1
- package/dist/store-ops.js +1 -106
- package/dist/store-ops.js.map +1 -1
- package/dist/testing/memory-store.cjs +1 -1
- package/dist/testing/memory-store.cjs.map +1 -1
- package/dist/testing/memory-store.js +1 -75
- package/dist/testing/memory-store.js.map +1 -1
- package/dist/testing.js +1 -2
- package/dist/types.d.ts +5 -4
- package/dist/types.d.ts.map +1 -1
- package/package.json +5 -5
package/dist/postmaster.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"postmaster.js","names":[],"sources":["../src/errors.ts","../src/definitions.ts","../src/_json.ts","../src/store-ops.ts","../src/postmaster.ts"],"sourcesContent":["export class PostmasterError extends Error {\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class PostmasterDisposedError extends PostmasterError {}\nexport class PostmasterJobError extends PostmasterError {}\n","import { PostmasterError } from './errors.ts';\nimport type { JobDefinition, JobDefinitions, RetryPolicy } from './types.ts';\n\nfunction validateRetry(retry: RetryPolicy | undefined, name: string): void {\n if (!retry) return;\n\n if (!Number.isInteger(retry.maxAttempts) || retry.maxAttempts < 1) {\n throw new PostmasterError(`job \"${name}\" retry.maxAttempts must be a positive integer`);\n }\n}\n\nfunction validateMigrations(name: string, job: JobDefinition<unknown>): void {\n const migrations = job.migrate;\n if (!migrations) return;\n\n const keys = Object.keys(migrations);\n if (keys.length === 0) throw new PostmasterError(`job \"${name}\" migrations must not be empty`);\n\n const versions = keys\n .map((key) => {\n const version = Number(key);\n if (!Number.isInteger(version) || String(version) !== key) {\n throw new PostmasterError(`job \"${name}\" has invalid migration key \"${key}\"`);\n }\n if (version < 1 || version >= job.version) {\n throw new PostmasterError(\n `job \"${name}\" has invalid migration key \"${version}\" (valid range: 1..${job.version - 1})`,\n );\n }\n if (typeof migrations[version] !== 'function') {\n throw new PostmasterError(`job \"${name}\" migration from version ${version} must be a function`);\n }\n return version;\n })\n .sort((a, b) => a - b);\n\n for (let index = 1; index < versions.length; index++) {\n if (versions[index] !== versions[index - 1] + 1) {\n throw new PostmasterError(`job \"${name}\" missing migration from version ${versions[index - 1] + 1}`);\n }\n }\n\n if (versions.at(-1) !== job.version - 1) {\n throw new PostmasterError(`job \"${name}\" migrations must lead into version ${job.version}`);\n }\n}\n\nfunction validateJob(name: string, job: JobDefinition<unknown>): void {\n if (!Number.isInteger(job.version) || job.version < 1) {\n throw new PostmasterError(`job \"${name}\" version must be a positive integer`);\n }\n\n if (typeof job.execute !== 'function' || typeof job.key !== 'function') {\n throw new PostmasterError(`job \"${name}\" must define execute and key`);\n }\n\n validateRetry(job.retry, name);\n validateMigrations(name, job);\n}\n\nexport function defineJobs<const J extends JobDefinitions>(jobs: J): J {\n for (const [name, job] of Object.entries(jobs)) validateJob(name, job);\n\n return jobs;\n}\n","import { PostmasterError } from './errors.ts';\nimport type { JsonValue, StoredFailure, Validate } from './types.ts';\n\nexport function runValidate<T>(validate: Validate<T> | undefined, value: unknown): T {\n if (!validate) return value as T;\n if (typeof validate === 'function') return validate(value);\n return validate.parse(value);\n}\n\nexport function asJsonValue(value: unknown): JsonValue {\n let serialized: string | undefined;\n\n try {\n serialized = JSON.stringify(value);\n } catch (error) {\n throw new PostmasterError('job payload must be JSON-serializable', { cause: error });\n }\n\n if (serialized === undefined) {\n throw new PostmasterError('job payload must be JSON-serializable');\n }\n\n return JSON.parse(serialized) as JsonValue;\n}\n\nexport function failureFrom(error: unknown, now: number): StoredFailure {\n if (error instanceof Error) {\n return { message: error.message, name: error.name, occurredAt: now };\n }\n\n return { message: String(error), name: 'Error', occurredAt: now };\n}\n\nexport function isAbortError(error: unknown): boolean {\n return error instanceof DOMException && error.name === 'AbortError';\n}\n","import { PostmasterJobError } from './errors.ts';\nimport type { PostmasterEntry, RemoveResult, RetryResult, StoredFailure, StoredJob, StoreTx } from './types.ts';\n\nexport interface ClaimParams {\n readonly leaseDuration: number;\n readonly now: number;\n readonly ownerId: string;\n}\n\nexport interface OwnedParams {\n readonly id: string;\n readonly now: number;\n readonly ownerId: string;\n}\n\nexport interface RescheduleParams extends OwnedParams {\n readonly availableAt: number;\n readonly failure: StoredFailure;\n}\n\nexport interface DeadLetterParams extends OwnedParams {\n readonly failure: StoredFailure;\n}\n\n/** Claim the earliest eligible job atomically. Returns the claimed entry or undefined. */\nexport async function claimJob(tx: StoreTx, params: ClaimParams): Promise<StoredJob | undefined> {\n const entry = await tx.findClaimable(params.now);\n if (!entry) return undefined;\n const claimed: StoredJob = {\n ...entry,\n attempts: entry.attempts + 1,\n failure: undefined,\n leaseExpiresAt: params.now + params.leaseDuration,\n ownerId: params.ownerId,\n status: 'running',\n updatedAt: params.now,\n };\n await tx.put(claimed);\n return claimed;\n}\n\n/** Complete and delete a job. Returns false if the owner is stale or the job is gone. */\nexport async function completeJob(tx: StoreTx, params: OwnedParams): Promise<boolean> {\n const entry = await tx.get(params.id);\n if (!entry || entry.status !== 'running' || entry.ownerId !== params.ownerId) return false;\n await tx.delete(params.id);\n return true;\n}\n\n/** Release a claimed job back to queued without consuming an attempt. Returns false if stale. */\nexport async function releaseJob(tx: StoreTx, params: OwnedParams): Promise<boolean> {\n const entry = await tx.get(params.id);\n if (!entry || entry.status !== 'running' || entry.ownerId !== params.ownerId) return false;\n await tx.put({\n ...entry,\n leaseExpiresAt: undefined,\n ownerId: undefined,\n status: 'queued',\n updatedAt: params.now,\n });\n return true;\n}\n\n/** Reschedule a running job back to queued with a future availableAt. Returns false if stale. */\nexport async function rescheduleJob(tx: StoreTx, params: RescheduleParams): Promise<boolean> {\n const entry = await tx.get(params.id);\n if (!entry || entry.status !== 'running' || entry.ownerId !== params.ownerId) return false;\n await tx.put({\n ...entry,\n availableAt: params.availableAt,\n failure: params.failure,\n leaseExpiresAt: undefined,\n ownerId: undefined,\n status: 'queued',\n updatedAt: params.now,\n });\n return true;\n}\n\n/** Move a running job to dead-letter. Returns false if stale. */\nexport async function deadLetterJob(tx: StoreTx, params: DeadLetterParams): Promise<boolean> {\n const entry = await tx.get(params.id);\n if (!entry || entry.status !== 'running' || entry.ownerId !== params.ownerId) return false;\n await tx.put({\n ...entry,\n failure: params.failure,\n leaseExpiresAt: undefined,\n ownerId: undefined,\n status: 'dead-letter',\n updatedAt: params.now,\n });\n return true;\n}\n\n/** Renew a lease for the current owner. Returns false if stale. */\nexport async function renewLeaseJob(tx: StoreTx, params: OwnedParams & { leaseExpiresAt: number }): Promise<boolean> {\n const entry = await tx.get(params.id);\n if (!entry || entry.status !== 'running' || entry.ownerId !== params.ownerId) return false;\n await tx.put({ ...entry, leaseExpiresAt: params.leaseExpiresAt, updatedAt: params.now });\n return true;\n}\n\n/** Retry a dead-letter job back to queued. Returns discriminated result. */\nexport async function retryJob(tx: StoreTx, id: string, now: number): Promise<RetryResult> {\n const entry = await tx.get(id);\n if (!entry) return { status: 'not-found' };\n if (entry.status === 'running') return { status: 'running' };\n if (entry.status !== 'dead-letter') return { status: 'not-dead-letter' };\n const retried: StoredJob = {\n ...entry,\n availableAt: now,\n failure: undefined,\n status: 'queued',\n updatedAt: now,\n };\n await tx.put(retried);\n return { entry: toEntry(retried), status: 'retried' };\n}\n\n/** Remove a queued or dead-letter job. Running jobs cannot be removed. */\nexport async function removeJob(tx: StoreTx, id: string): Promise<RemoveResult> {\n const entry = await tx.get(id);\n if (!entry) return { status: 'not-found' };\n if (entry.status === 'running') return { status: 'running' };\n await tx.delete(id);\n return { id, status: 'removed' };\n}\n\n/** Enqueue a new job. Rejects duplicate ids. */\nexport async function enqueueJob(tx: StoreTx, entry: StoredJob): Promise<void> {\n const existing = await tx.get(entry.id);\n if (existing) throw new PostmasterJobError(`Postmaster entry \"${entry.id}\" already exists`);\n await tx.put(entry);\n}\n\nexport function toEntry(entry: StoredJob): PostmasterEntry {\n return {\n attempts: entry.attempts,\n availableAt: entry.availableAt,\n createdAt: entry.createdAt,\n ...(entry.failure ? { failure: entry.failure } : {}),\n id: entry.id,\n key: entry.key,\n name: entry.name,\n status: entry.status,\n updatedAt: entry.updatedAt,\n version: entry.version,\n };\n}\n","import { backoff } from '@vielzeug/arsenal';\nimport { asJsonValue, failureFrom, isAbortError, runValidate } from './_json.ts';\nimport { PostmasterDisposedError, PostmasterError, PostmasterJobError } from './errors.ts';\nimport {\n claimJob,\n completeJob,\n deadLetterJob,\n enqueueJob,\n releaseJob,\n removeJob,\n renewLeaseJob,\n rescheduleJob,\n retryJob,\n toEntry,\n} from './store-ops.ts';\nimport type {\n CreatePostmasterOptions,\n EnqueueOptions,\n EntryFilter,\n FlushResult,\n InferJobPayload,\n JobContext,\n JobDefinition,\n JobDefinitions,\n Postmaster,\n PostmasterEntry,\n PostmasterEvent,\n PostmasterStats,\n RemoveResult,\n RetryResult,\n StoredJob,\n} from './types.ts';\n\ntype ExecutionResult = Omit<FlushResult, 'processed'> & { processed: boolean };\ntype MutableFlushResult = { -readonly [K in keyof FlushResult]: FlushResult[K] };\n\nconst emptyResult = (): FlushResult => ({ completed: 0, deadLettered: 0, processed: 0, retryScheduled: 0 });\n\nfunction assertLeaseDuration(value: number): void {\n if (!Number.isInteger(value) || value < 1_000) {\n throw new PostmasterError('leaseDuration must be a positive integer of at least 1000ms');\n }\n}\n\nfunction assertAvailableAt(value: number | undefined, defaultValue: number): number {\n if (value === undefined) return defaultValue;\n if (!Number.isFinite(value) || value < 0 || !Number.isSafeInteger(value)) {\n throw new PostmasterError('availableAt must be a finite non-negative safe integer');\n }\n return value;\n}\n\nexport function createPostmaster<J extends JobDefinitions>(options: CreatePostmasterOptions<J>): Postmaster<J> {\n const { clock = Date.now, jobs, leaseDuration = 30_000, signal, store } = options;\n assertLeaseDuration(leaseDuration);\n\n const controller = new AbortController();\n const ownerId = crypto.randomUUID();\n const tappers = new Set<(event: PostmasterEvent) => void>();\n let disposed = false;\n let started = false;\n let running: Promise<void> | undefined;\n let wakeTimer: ReturnType<typeof setTimeout> | undefined;\n const activeEntries = new Map<string, StoredJob>();\n let flushPromise: Promise<FlushResult> | undefined;\n\n const error = (reason: unknown): void => {\n const value = reason instanceof Error ? reason : new Error(String(reason));\n emitTap({ error: value, type: 'processor-error' });\n };\n\n const emitTap = (event: PostmasterEvent): void => {\n if (tappers.size === 0) return;\n for (const tapper of tappers) {\n try {\n tapper(event);\n } catch {\n // Observability must not affect postmaster behavior.\n }\n }\n };\n\n const assertLive = (): void => {\n if (disposed) throw new PostmasterDisposedError('Postmaster is disposed');\n };\n\n const clearWakeTimer = (): void => {\n if (wakeTimer !== undefined) clearTimeout(wakeTimer);\n wakeTimer = undefined;\n };\n\n const wake = (): void => {\n clearWakeTimer();\n if (started && !disposed) pump();\n };\n\n const schedule = async (): Promise<void> => {\n if (!started || disposed) return;\n const next = await store.transact((tx) => tx.findNextWake(clock()));\n if (next === undefined) return;\n const delay = Math.max(0, Math.min(next - clock(), 2_147_483_647));\n wakeTimer = setTimeout(wake, delay);\n };\n\n const resolveJob = (entry: StoredJob): JobDefinition<unknown> => {\n const job = jobs[entry.name];\n if (!job) throw new PostmasterJobError(`no job definition is registered for \"${entry.name}\"`);\n return job;\n };\n\n const deadLetter = async (entry: StoredJob, reason: unknown): Promise<ExecutionResult> => {\n const finalized = await store.transact((tx) =>\n deadLetterJob(tx, { failure: failureFrom(reason, clock()), id: entry.id, now: clock(), ownerId }),\n );\n\n if (!finalized) {\n emitTap({ id: entry.id, type: 'lease-lost' });\n return { completed: 0, deadLettered: 0, processed: true, retryScheduled: 0 };\n }\n\n emitTap({ entry: toEntry({ ...entry, status: 'dead-letter' }), type: 'dead-lettered' });\n return { completed: 0, deadLettered: 1, processed: true, retryScheduled: 0 };\n };\n\n const execute = async (entry: StoredJob, externalSignal?: AbortSignal): Promise<ExecutionResult> => {\n let job: JobDefinition<unknown>;\n let payload: unknown;\n\n try {\n job = resolveJob(entry);\n if (entry.version > job.version) {\n throw new PostmasterJobError(\n `job \"${entry.name}\" version ${entry.version} is newer than the registered version`,\n );\n }\n let raw: unknown = entry.payload;\n if (entry.version < job.version) {\n const migrations = job.migrate;\n if (!migrations) {\n throw new PostmasterJobError(`job \"${entry.name}\" has no migrations`);\n }\n for (let v = entry.version; v < job.version; v++) {\n const step = migrations[v];\n if (typeof step !== 'function') {\n throw new PostmasterJobError(`job \"${entry.name}\" does not support stored version ${entry.version}`);\n }\n raw = step(raw);\n if (raw === undefined) {\n throw new PostmasterJobError(`job \"${entry.name}\" migration from version ${v} returned undefined`);\n }\n }\n }\n payload = runValidate(job.validate, raw);\n } catch (reason) {\n return deadLetter(entry, reason);\n }\n\n const taskController = new AbortController();\n const taskSignal = AbortSignal.any(\n [controller.signal, externalSignal, taskController.signal].filter((s): s is AbortSignal => s !== undefined),\n );\n const heartbeat = setInterval(\n () => {\n void store\n .transact((tx) =>\n renewLeaseJob(tx, { id: entry.id, leaseExpiresAt: clock() + leaseDuration, now: clock(), ownerId }),\n )\n .then((renewed) => {\n if (!renewed) {\n taskController.abort();\n emitTap({ id: entry.id, type: 'lease-lost' });\n }\n })\n .catch(error);\n },\n Math.max(1_000, Math.floor(leaseDuration / 2)),\n );\n\n emitTap({ entry: toEntry(entry), type: 'started' });\n\n try {\n await job.execute(payload, {\n attempt: entry.attempts,\n entryId: entry.id,\n key: entry.key,\n signal: taskSignal,\n } as JobContext);\n\n if (taskSignal.aborted) {\n await store.transact((tx) => releaseJob(tx, { id: entry.id, now: clock(), ownerId }));\n return { completed: 0, deadLettered: 0, processed: true, retryScheduled: 0 };\n }\n\n const completed = await store.transact((tx) => completeJob(tx, { id: entry.id, now: clock(), ownerId }));\n if (!completed) {\n emitTap({ id: entry.id, type: 'lease-lost' });\n return { completed: 0, deadLettered: 0, processed: true, retryScheduled: 0 };\n }\n\n emitTap({ entry: toEntry(entry), type: 'completed' });\n return { completed: 1, deadLettered: 0, processed: true, retryScheduled: 0 };\n } catch (reason) {\n if (taskSignal.aborted || isAbortError(reason)) {\n await store.transact((tx) => releaseJob(tx, { id: entry.id, now: clock(), ownerId }));\n return { completed: 0, deadLettered: 0, processed: true, retryScheduled: 0 };\n }\n\n let shouldRetry = false;\n let delay = 0;\n\n try {\n shouldRetry =\n entry.attempts < (job.retry?.maxAttempts ?? 1) && (job.retry?.shouldRetry(reason, entry.attempts) ?? false);\n if (!shouldRetry) return deadLetter(entry, reason);\n delay = job.retry?.delay?.(entry.attempts - 1) ?? backoff(entry.attempts - 1);\n if (!Number.isFinite(delay) || delay < 0) {\n throw new PostmasterError(`job \"${entry.name}\" retry delay must be finite and non-negative`);\n }\n } catch (retryReason) {\n return deadLetter(entry, retryReason);\n }\n\n const availableAt = clock() + delay;\n const rescheduled = await store.transact((tx) =>\n rescheduleJob(tx, { availableAt, failure: failureFrom(reason, clock()), id: entry.id, now: clock(), ownerId }),\n );\n if (!rescheduled) {\n emitTap({ id: entry.id, type: 'lease-lost' });\n return { completed: 0, deadLettered: 0, processed: true, retryScheduled: 0 };\n }\n emitTap({ entry: toEntry({ ...entry, availableAt, status: 'queued' }), type: 'retry-scheduled' });\n return { completed: 0, deadLettered: 0, processed: true, retryScheduled: 1 };\n } finally {\n clearInterval(heartbeat);\n }\n };\n\n const processNext = async (externalSignal?: AbortSignal): Promise<ExecutionResult> => {\n if (externalSignal?.aborted) throw new DOMException('The operation was aborted', 'AbortError');\n if (controller.signal.aborted) return { completed: 0, deadLettered: 0, processed: false, retryScheduled: 0 };\n const entry = await store.transact((tx) => claimJob(tx, { leaseDuration, now: clock(), ownerId }));\n if (!entry) return { completed: 0, deadLettered: 0, processed: false, retryScheduled: 0 };\n activeEntries.set(entry.id, entry);\n try {\n return await execute(entry, externalSignal);\n } finally {\n activeEntries.delete(entry.id);\n }\n };\n\n const pump = (): void => {\n if (running || disposed) return;\n running = (async () => {\n for (;;) {\n const result = await processNext();\n if (!result.processed || disposed) break;\n }\n await schedule();\n })()\n .catch(error)\n .finally(() => {\n running = undefined;\n });\n };\n\n const unsubscribeStore = store.subscribe(wake);\n const externalAbort = (): void => {\n void dispose();\n };\n signal?.addEventListener('abort', externalAbort, { once: true });\n\n const dispose = async (): Promise<void> => {\n if (disposed) return;\n disposed = true;\n emitTap({ type: 'dispose' });\n tappers.clear();\n clearWakeTimer();\n signal?.removeEventListener('abort', externalAbort);\n unsubscribeStore();\n controller.abort();\n const entries = [...activeEntries.values()];\n activeEntries.clear();\n await Promise.all(\n entries.map((entry) => store.transact((tx) => releaseJob(tx, { id: entry.id, now: clock(), ownerId }))),\n );\n };\n\n return {\n get disposalSignal() {\n return controller.signal;\n },\n async dispose(): Promise<void> {\n await dispose();\n },\n get disposed() {\n return disposed;\n },\n async enqueue<K extends keyof J & string>(\n name: K,\n payload: InferJobPayload<J[K]>,\n options?: EnqueueOptions,\n ): Promise<PostmasterEntry> {\n assertLive();\n const job = jobs[name];\n if (!job) throw new PostmasterJobError(`no job definition is registered for \"${name}\"`);\n const now = clock();\n const availableAt = assertAvailableAt(options?.availableAt, now);\n const parsed = runValidate(job.validate, payload);\n const key = job.key(parsed);\n if (typeof key !== 'string' || key.length === 0) {\n throw new PostmasterError(`job \"${name}\" returned an empty key`);\n }\n const entry: StoredJob = {\n attempts: 0,\n availableAt,\n createdAt: now,\n id: crypto.randomUUID(),\n key,\n name,\n payload: asJsonValue(parsed),\n status: 'queued',\n updatedAt: now,\n version: job.version,\n };\n await store.transact((tx) => enqueueJob(tx, entry));\n const result = toEntry(entry);\n emitTap({ entry: result, type: 'enqueued' });\n wake();\n return result;\n },\n flush(options?: { signal?: AbortSignal }): Promise<FlushResult> {\n assertLive();\n if (flushPromise) return flushPromise;\n clearWakeTimer();\n const promise = (async (): Promise<FlushResult> => {\n await running;\n const result: MutableFlushResult = emptyResult();\n try {\n for (;;) {\n const next = await processNext(options?.signal);\n if (!next.processed) return result;\n result.processed += 1;\n result.completed += next.completed;\n result.deadLettered += next.deadLettered;\n result.retryScheduled += next.retryScheduled;\n if (disposed) return result;\n }\n } finally {\n flushPromise = undefined;\n wake();\n }\n })();\n flushPromise = promise;\n return promise;\n },\n async list(filter?: EntryFilter): Promise<PostmasterEntry[]> {\n assertLive();\n return (await store.list(filter)).map(toEntry);\n },\n async remove(id: string): Promise<RemoveResult> {\n assertLive();\n const result = await store.transact((tx) => removeJob(tx, id));\n if (result.status === 'removed') emitTap({ id, type: 'removed' });\n return result;\n },\n async retry(id: string): Promise<RetryResult> {\n assertLive();\n const result = await store.transact((tx) => retryJob(tx, id, clock()));\n if (result.status === 'retried') wake();\n return result;\n },\n start(): void {\n assertLive();\n if (started) return;\n started = true;\n wake();\n },\n async stats(): Promise<PostmasterStats> {\n assertLive();\n return store.transact((tx) => tx.countByStatus());\n },\n tap(handler: (event: PostmasterEvent) => void, opts?: { readonly signal?: AbortSignal }): () => void {\n assertLive();\n tappers.add(handler);\n\n if (opts?.signal) {\n if (opts.signal.aborted) {\n tappers.delete(handler);\n return () => {};\n }\n const onAbort = () => tappers.delete(handler);\n opts.signal.addEventListener('abort', onAbort, { once: true });\n return () => {\n tappers.delete(handler);\n opts.signal?.removeEventListener('abort', onAbort);\n };\n }\n\n return () => tappers.delete(handler);\n },\n async [Symbol.asyncDispose](): Promise<void> {\n await dispose();\n },\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"postmaster.js","names":[],"sources":["../src/errors.ts","../src/definitions.ts","../src/_json.ts","../src/store-ops.ts","../src/postmaster.ts"],"sourcesContent":["export class PostmasterError extends Error {\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class PostmasterDisposedError extends PostmasterError {}\nexport class PostmasterJobError extends PostmasterError {}\n","import { PostmasterError } from './errors.ts';\nimport type { JobDefinition, JobDefinitions, RetryPolicy } from './types.ts';\n\nfunction validateRetry(retry: RetryPolicy | undefined, name: string): void {\n if (!retry) return;\n\n if (!Number.isInteger(retry.maxAttempts) || retry.maxAttempts < 1) {\n throw new PostmasterError(`job \"${name}\" retry.maxAttempts must be a positive integer`);\n }\n}\n\nfunction validateMigrations(name: string, job: JobDefinition<unknown>): void {\n const migrations = job.migrate;\n if (!migrations) return;\n\n const keys = Object.keys(migrations);\n if (keys.length === 0) throw new PostmasterError(`job \"${name}\" migrations must not be empty`);\n\n const versions = keys\n .map((key) => {\n const version = Number(key);\n if (!Number.isInteger(version) || String(version) !== key) {\n throw new PostmasterError(`job \"${name}\" has invalid migration key \"${key}\"`);\n }\n if (version < 1 || version >= job.version) {\n throw new PostmasterError(\n `job \"${name}\" has invalid migration key \"${version}\" (valid range: 1..${job.version - 1})`,\n );\n }\n if (typeof migrations[version] !== 'function') {\n throw new PostmasterError(`job \"${name}\" migration from version ${version} must be a function`);\n }\n return version;\n })\n .sort((a, b) => a - b);\n\n for (let index = 1; index < versions.length; index++) {\n if (versions[index] !== versions[index - 1] + 1) {\n throw new PostmasterError(`job \"${name}\" missing migration from version ${versions[index - 1] + 1}`);\n }\n }\n\n if (versions.at(-1) !== job.version - 1) {\n throw new PostmasterError(`job \"${name}\" migrations must lead into version ${job.version}`);\n }\n}\n\nfunction validateJob(name: string, job: JobDefinition<unknown>): void {\n if (!Number.isInteger(job.version) || job.version < 1) {\n throw new PostmasterError(`job \"${name}\" version must be a positive integer`);\n }\n\n if (typeof job.execute !== 'function' || typeof job.key !== 'function') {\n throw new PostmasterError(`job \"${name}\" must define execute and key`);\n }\n\n validateRetry(job.retry, name);\n validateMigrations(name, job);\n}\n\nexport function defineJobs<const J extends JobDefinitions>(jobs: J): J {\n for (const [name, job] of Object.entries(jobs)) validateJob(name, job);\n\n return jobs;\n}\n","import { PostmasterError } from './errors.ts';\nimport type { JsonValue, StoredFailure, Validate } from './types.ts';\n\nexport function runValidate<T>(validate: Validate<T> | undefined, value: unknown): T {\n if (!validate) return value as T;\n if (typeof validate === 'function') return validate(value);\n return validate.parse(value);\n}\n\nexport function asJsonValue(value: unknown): JsonValue {\n let serialized: string | undefined;\n\n try {\n serialized = JSON.stringify(value);\n } catch (error) {\n throw new PostmasterError('job payload must be JSON-serializable', { cause: error });\n }\n\n if (serialized === undefined) {\n throw new PostmasterError('job payload must be JSON-serializable');\n }\n\n return JSON.parse(serialized) as JsonValue;\n}\n\nexport function failureFrom(error: unknown, now: number): StoredFailure {\n if (error instanceof Error) {\n return { message: error.message, name: error.name, occurredAt: now };\n }\n\n return { message: String(error), name: 'Error', occurredAt: now };\n}\n\nexport function isAbortError(error: unknown): boolean {\n return error instanceof DOMException && error.name === 'AbortError';\n}\n","import { PostmasterJobError } from './errors.ts';\nimport type { PostmasterEntry, RemoveResult, RequeueResult, StoredFailure, StoredJob, StoreTx } from './types.ts';\n\nexport interface ClaimParams {\n readonly leaseDuration: number;\n readonly now: number;\n readonly ownerId: string;\n}\n\nexport interface OwnedParams {\n readonly id: string;\n readonly now: number;\n readonly ownerId: string;\n}\n\nexport interface RescheduleParams extends OwnedParams {\n readonly availableAt: number;\n readonly failure: StoredFailure;\n}\n\nexport interface DeadLetterParams extends OwnedParams {\n readonly failure: StoredFailure;\n}\n\n/** Claim the earliest eligible job atomically. Returns the claimed entry or undefined. */\nexport async function claimJob(tx: StoreTx, params: ClaimParams): Promise<StoredJob | undefined> {\n const entry = await tx.findClaimable(params.now);\n if (!entry) return undefined;\n const claimed: StoredJob = {\n ...entry,\n attempts: entry.attempts + 1,\n failure: undefined,\n leaseExpiresAt: params.now + params.leaseDuration,\n ownerId: params.ownerId,\n status: 'running',\n updatedAt: params.now,\n };\n await tx.put(claimed);\n return claimed;\n}\n\n/** Complete and delete a job. Returns false if the owner is stale or the job is gone. */\nexport async function completeJob(tx: StoreTx, params: OwnedParams): Promise<boolean> {\n const entry = await tx.get(params.id);\n if (!entry || entry.status !== 'running' || entry.ownerId !== params.ownerId) return false;\n await tx.delete(params.id);\n return true;\n}\n\n/** Release a claimed job back to queued without consuming an attempt. Returns false if stale. */\nexport async function releaseJob(tx: StoreTx, params: OwnedParams): Promise<boolean> {\n const entry = await tx.get(params.id);\n if (!entry || entry.status !== 'running' || entry.ownerId !== params.ownerId) return false;\n await tx.put({\n ...entry,\n leaseExpiresAt: undefined,\n ownerId: undefined,\n status: 'queued',\n updatedAt: params.now,\n });\n return true;\n}\n\n/** Reschedule a running job back to queued with a future availableAt. Returns false if stale. */\nexport async function rescheduleJob(tx: StoreTx, params: RescheduleParams): Promise<boolean> {\n const entry = await tx.get(params.id);\n if (!entry || entry.status !== 'running' || entry.ownerId !== params.ownerId) return false;\n await tx.put({\n ...entry,\n availableAt: params.availableAt,\n failure: params.failure,\n leaseExpiresAt: undefined,\n ownerId: undefined,\n status: 'queued',\n updatedAt: params.now,\n });\n return true;\n}\n\n/** Move a running job to dead-letter. Returns false if stale. */\nexport async function deadLetterJob(tx: StoreTx, params: DeadLetterParams): Promise<boolean> {\n const entry = await tx.get(params.id);\n if (!entry || entry.status !== 'running' || entry.ownerId !== params.ownerId) return false;\n await tx.put({\n ...entry,\n failure: params.failure,\n leaseExpiresAt: undefined,\n ownerId: undefined,\n status: 'dead-letter',\n updatedAt: params.now,\n });\n return true;\n}\n\n/** Renew a lease for the current owner. Returns false if stale. */\nexport async function renewLeaseJob(tx: StoreTx, params: OwnedParams & { leaseExpiresAt: number }): Promise<boolean> {\n const entry = await tx.get(params.id);\n if (!entry || entry.status !== 'running' || entry.ownerId !== params.ownerId) return false;\n await tx.put({ ...entry, leaseExpiresAt: params.leaseExpiresAt, updatedAt: params.now });\n return true;\n}\n\n/** Requeue a dead-letter job back to queued. Returns discriminated result. */\nexport async function requeueJob(tx: StoreTx, id: string, now: number): Promise<RequeueResult> {\n const entry = await tx.get(id);\n if (!entry) return { status: 'not-found' };\n if (entry.status === 'running') return { status: 'running' };\n if (entry.status !== 'dead-letter') return { status: 'not-dead-letter' };\n const requeued: StoredJob = {\n ...entry,\n availableAt: now,\n failure: undefined,\n status: 'queued',\n updatedAt: now,\n };\n await tx.put(requeued);\n return { entry: toEntry(requeued), status: 'requeued' };\n}\n\n/** Remove a queued or dead-letter job. Running jobs cannot be removed. */\nexport async function removeJob(tx: StoreTx, id: string): Promise<RemoveResult> {\n const entry = await tx.get(id);\n if (!entry) return { status: 'not-found' };\n if (entry.status === 'running') return { status: 'running' };\n await tx.delete(id);\n return { id, status: 'removed' };\n}\n\n/** Enqueue a new job. Rejects duplicate ids. */\nexport async function enqueueJob(tx: StoreTx, entry: StoredJob): Promise<void> {\n const existing = await tx.get(entry.id);\n if (existing) throw new PostmasterJobError(`Postmaster entry \"${entry.id}\" already exists`);\n await tx.put(entry);\n}\n\nexport function toEntry(entry: StoredJob): PostmasterEntry {\n return {\n attempts: entry.attempts,\n availableAt: entry.availableAt,\n createdAt: entry.createdAt,\n ...(entry.failure ? { failure: entry.failure } : {}),\n id: entry.id,\n key: entry.key,\n name: entry.name,\n status: entry.status,\n updatedAt: entry.updatedAt,\n version: entry.version,\n };\n}\n","import { backoff, tapper } from '@vielzeug/arsenal';\nimport { asJsonValue, failureFrom, isAbortError, runValidate } from './_json.ts';\nimport { PostmasterDisposedError, PostmasterError, PostmasterJobError } from './errors.ts';\nimport {\n claimJob,\n completeJob,\n deadLetterJob,\n enqueueJob,\n releaseJob,\n removeJob,\n renewLeaseJob,\n requeueJob,\n rescheduleJob,\n toEntry,\n} from './store-ops.ts';\nimport type {\n CreatePostmasterOptions,\n EnqueueOptions,\n EntryFilter,\n FlushResult,\n InferJobPayload,\n JobContext,\n JobDefinition,\n JobDefinitions,\n Postmaster,\n PostmasterEntry,\n PostmasterEvent,\n PostmasterStats,\n RemoveResult,\n RequeueResult,\n StoredJob,\n} from './types.ts';\n\ntype ExecutionResult = Omit<FlushResult, 'processed'> & { processed: boolean };\ntype MutableFlushResult = { -readonly [K in keyof FlushResult]: FlushResult[K] };\n\nconst emptyResult = (): FlushResult => ({ completed: 0, deadLettered: 0, processed: 0, retryScheduled: 0 });\n\nfunction assertLeaseDuration(value: number): void {\n if (!Number.isInteger(value) || value < 1_000) {\n throw new PostmasterError('leaseDuration must be a positive integer of at least 1000ms');\n }\n}\n\nfunction assertAvailableAt(value: number | undefined, defaultValue: number): number {\n if (value === undefined) return defaultValue;\n if (!Number.isFinite(value) || value < 0 || !Number.isSafeInteger(value)) {\n throw new PostmasterError('availableAt must be a finite non-negative safe integer');\n }\n return value;\n}\n\nexport function createPostmaster<J extends JobDefinitions>(options: CreatePostmasterOptions<J>): Postmaster<J> {\n const { clock = Date.now, jobs, leaseDuration = 30_000, signal, store } = options;\n assertLeaseDuration(leaseDuration);\n\n const controller = new AbortController();\n const ownerId = crypto.randomUUID();\n const tappers = tapper<PostmasterEvent>();\n let disposed = false;\n let started = false;\n let running: Promise<void> | undefined;\n let wakeTimer: ReturnType<typeof setTimeout> | undefined;\n const activeEntries = new Map<string, StoredJob>();\n let flushPromise: Promise<FlushResult> | undefined;\n\n const error = (reason: unknown): void => {\n const value = reason instanceof Error ? reason : new Error(String(reason));\n emitTap({ error: value, type: 'processor-error' });\n };\n\n const emitTap = (event: PostmasterEvent): void => {\n tappers.emit(event);\n };\n\n const assertLive = (): void => {\n if (disposed) throw new PostmasterDisposedError('Postmaster is disposed');\n };\n\n const clearWakeTimer = (): void => {\n if (wakeTimer !== undefined) clearTimeout(wakeTimer);\n wakeTimer = undefined;\n };\n\n const wake = (): void => {\n clearWakeTimer();\n if (started && !disposed) pump();\n };\n\n const schedule = async (): Promise<void> => {\n if (!started || disposed) return;\n const next = await store.transact((tx) => tx.findNextWake(clock()));\n if (next === undefined) return;\n const delay = Math.max(0, Math.min(next - clock(), 2_147_483_647));\n wakeTimer = setTimeout(wake, delay);\n };\n\n const resolveJob = (entry: StoredJob): JobDefinition<unknown> => {\n const job = jobs[entry.name];\n if (!job) throw new PostmasterJobError(`no job definition is registered for \"${entry.name}\"`);\n return job;\n };\n\n const deadLetter = async (entry: StoredJob, reason: unknown): Promise<ExecutionResult> => {\n const finalized = await store.transact((tx) =>\n deadLetterJob(tx, { failure: failureFrom(reason, clock()), id: entry.id, now: clock(), ownerId }),\n );\n\n if (!finalized) {\n emitTap({ id: entry.id, type: 'lease-lost' });\n return { completed: 0, deadLettered: 0, processed: true, retryScheduled: 0 };\n }\n\n emitTap({ entry: toEntry({ ...entry, status: 'dead-letter' }), type: 'dead-lettered' });\n return { completed: 0, deadLettered: 1, processed: true, retryScheduled: 0 };\n };\n\n const execute = async (entry: StoredJob, externalSignal?: AbortSignal): Promise<ExecutionResult> => {\n let job: JobDefinition<unknown>;\n let payload: unknown;\n\n try {\n job = resolveJob(entry);\n if (entry.version > job.version) {\n throw new PostmasterJobError(\n `job \"${entry.name}\" version ${entry.version} is newer than the registered version`,\n );\n }\n let raw: unknown = entry.payload;\n if (entry.version < job.version) {\n const migrations = job.migrate;\n if (!migrations) {\n throw new PostmasterJobError(`job \"${entry.name}\" has no migrations`);\n }\n for (let v = entry.version; v < job.version; v++) {\n const step = migrations[v];\n if (typeof step !== 'function') {\n throw new PostmasterJobError(`job \"${entry.name}\" does not support stored version ${entry.version}`);\n }\n raw = step(raw);\n if (raw === undefined) {\n throw new PostmasterJobError(`job \"${entry.name}\" migration from version ${v} returned undefined`);\n }\n }\n }\n payload = runValidate(job.validate, raw);\n } catch (reason) {\n return deadLetter(entry, reason);\n }\n\n const taskController = new AbortController();\n const taskSignal = AbortSignal.any(\n [controller.signal, externalSignal, taskController.signal].filter((s): s is AbortSignal => s !== undefined),\n );\n const heartbeat = setInterval(\n () => {\n void store\n .transact((tx) =>\n renewLeaseJob(tx, { id: entry.id, leaseExpiresAt: clock() + leaseDuration, now: clock(), ownerId }),\n )\n .then((renewed) => {\n if (!renewed) {\n taskController.abort();\n emitTap({ id: entry.id, type: 'lease-lost' });\n }\n })\n .catch(error);\n },\n Math.max(1_000, Math.floor(leaseDuration / 2)),\n );\n\n emitTap({ entry: toEntry(entry), type: 'started' });\n\n try {\n await job.execute(payload, {\n attempt: entry.attempts,\n entryId: entry.id,\n key: entry.key,\n signal: taskSignal,\n } as JobContext);\n\n if (taskSignal.aborted) {\n await store.transact((tx) => releaseJob(tx, { id: entry.id, now: clock(), ownerId }));\n return { completed: 0, deadLettered: 0, processed: true, retryScheduled: 0 };\n }\n\n const completed = await store.transact((tx) => completeJob(tx, { id: entry.id, now: clock(), ownerId }));\n if (!completed) {\n emitTap({ id: entry.id, type: 'lease-lost' });\n return { completed: 0, deadLettered: 0, processed: true, retryScheduled: 0 };\n }\n\n emitTap({ entry: toEntry(entry), type: 'completed' });\n return { completed: 1, deadLettered: 0, processed: true, retryScheduled: 0 };\n } catch (reason) {\n if (taskSignal.aborted || isAbortError(reason)) {\n await store.transact((tx) => releaseJob(tx, { id: entry.id, now: clock(), ownerId }));\n return { completed: 0, deadLettered: 0, processed: true, retryScheduled: 0 };\n }\n\n let shouldRetry = false;\n let delay = 0;\n\n try {\n shouldRetry =\n entry.attempts < (job.retry?.maxAttempts ?? 1) && (job.retry?.shouldRetry?.(reason, entry.attempts) ?? true);\n if (!shouldRetry) return deadLetter(entry, reason);\n delay = job.retry?.delay?.(entry.attempts - 1) ?? backoff(entry.attempts - 1);\n if (!Number.isFinite(delay) || delay < 0) {\n throw new PostmasterError(`job \"${entry.name}\" retry delay must be finite and non-negative`);\n }\n } catch (retryReason) {\n return deadLetter(entry, retryReason);\n }\n\n const availableAt = clock() + delay;\n const rescheduled = await store.transact((tx) =>\n rescheduleJob(tx, { availableAt, failure: failureFrom(reason, clock()), id: entry.id, now: clock(), ownerId }),\n );\n if (!rescheduled) {\n emitTap({ id: entry.id, type: 'lease-lost' });\n return { completed: 0, deadLettered: 0, processed: true, retryScheduled: 0 };\n }\n emitTap({ entry: toEntry({ ...entry, availableAt, status: 'queued' }), type: 'retry-scheduled' });\n return { completed: 0, deadLettered: 0, processed: true, retryScheduled: 1 };\n } finally {\n clearInterval(heartbeat);\n }\n };\n\n const processNext = async (externalSignal?: AbortSignal): Promise<ExecutionResult> => {\n if (externalSignal?.aborted) throw new DOMException('The operation was aborted', 'AbortError');\n if (controller.signal.aborted) return { completed: 0, deadLettered: 0, processed: false, retryScheduled: 0 };\n const entry = await store.transact((tx) => claimJob(tx, { leaseDuration, now: clock(), ownerId }));\n if (!entry) return { completed: 0, deadLettered: 0, processed: false, retryScheduled: 0 };\n activeEntries.set(entry.id, entry);\n try {\n return await execute(entry, externalSignal);\n } finally {\n activeEntries.delete(entry.id);\n }\n };\n\n const pump = (): void => {\n if (running || disposed) return;\n running = (async () => {\n for (;;) {\n const result = await processNext();\n if (!result.processed || disposed) break;\n }\n await schedule();\n })()\n .catch(error)\n .finally(() => {\n running = undefined;\n });\n };\n\n const unsubscribeStore = store.subscribe(wake);\n const externalAbort = (): void => {\n void dispose();\n };\n signal?.addEventListener('abort', externalAbort, { once: true });\n\n const dispose = async (): Promise<void> => {\n if (disposed) return;\n disposed = true;\n emitTap({ type: 'dispose' });\n tappers.clear();\n clearWakeTimer();\n signal?.removeEventListener('abort', externalAbort);\n unsubscribeStore();\n controller.abort();\n const entries = [...activeEntries.values()];\n activeEntries.clear();\n await Promise.all(\n entries.map((entry) => store.transact((tx) => releaseJob(tx, { id: entry.id, now: clock(), ownerId }))),\n );\n };\n\n return {\n get disposalSignal() {\n return controller.signal;\n },\n async dispose(): Promise<void> {\n await dispose();\n },\n get disposed() {\n return disposed;\n },\n async enqueue<K extends keyof J & string>(\n name: K,\n payload: InferJobPayload<J[K]>,\n options?: EnqueueOptions,\n ): Promise<PostmasterEntry> {\n assertLive();\n const job = jobs[name];\n if (!job) throw new PostmasterJobError(`no job definition is registered for \"${name}\"`);\n const now = clock();\n const availableAt = assertAvailableAt(options?.availableAt, now);\n const parsed = runValidate(job.validate, payload);\n const key = job.key(parsed);\n if (typeof key !== 'string' || key.length === 0) {\n throw new PostmasterError(`job \"${name}\" returned an empty key`);\n }\n const entry: StoredJob = {\n attempts: 0,\n availableAt,\n createdAt: now,\n id: crypto.randomUUID(),\n key,\n name,\n payload: asJsonValue(parsed),\n status: 'queued',\n updatedAt: now,\n version: job.version,\n };\n await store.transact((tx) => enqueueJob(tx, entry));\n const result = toEntry(entry);\n emitTap({ entry: result, type: 'enqueued' });\n wake();\n return result;\n },\n flush(options?: { signal?: AbortSignal }): Promise<FlushResult> {\n assertLive();\n if (flushPromise) return flushPromise;\n clearWakeTimer();\n const promise = (async (): Promise<FlushResult> => {\n await running;\n const result: MutableFlushResult = emptyResult();\n try {\n for (;;) {\n const next = await processNext(options?.signal);\n if (!next.processed) return result;\n result.processed += 1;\n result.completed += next.completed;\n result.deadLettered += next.deadLettered;\n result.retryScheduled += next.retryScheduled;\n if (disposed) return result;\n }\n } finally {\n flushPromise = undefined;\n wake();\n }\n })();\n flushPromise = promise;\n return promise;\n },\n async list(filter?: EntryFilter): Promise<PostmasterEntry[]> {\n assertLive();\n return (await store.list(filter)).map(toEntry);\n },\n async remove(id: string): Promise<RemoveResult> {\n assertLive();\n const result = await store.transact((tx) => removeJob(tx, id));\n if (result.status === 'removed') emitTap({ id, type: 'removed' });\n return result;\n },\n async requeue(id: string): Promise<RequeueResult> {\n assertLive();\n const result = await store.transact((tx) => requeueJob(tx, id, clock()));\n if (result.status === 'requeued') wake();\n return result;\n },\n start(): void {\n assertLive();\n if (started) return;\n started = true;\n wake();\n },\n async stats(): Promise<PostmasterStats> {\n assertLive();\n return store.transact((tx) => tx.countByStatus());\n },\n tap(handler: (event: PostmasterEvent) => void, opts?: { readonly signal?: AbortSignal }): () => void {\n assertLive();\n\n return tappers.tap(handler, opts);\n },\n async [Symbol.asyncDispose](): Promise<void> {\n await dispose();\n },\n };\n}\n"],"mappings":"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"}
|
package/dist/store-ops.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("./errors.cjs");async function
|
|
1
|
+
const e=require("./errors.cjs");async function claimJob(e,t){let n=await e.findClaimable(t.now);if(!n)return;let r={...n,attempts:n.attempts+1,failure:void 0,leaseExpiresAt:t.now+t.leaseDuration,ownerId:t.ownerId,status:`running`,updatedAt:t.now};return await e.put(r),r}async function completeJob(e,t){let n=await e.get(t.id);return!n||n.status!==`running`||n.ownerId!==t.ownerId?!1:(await e.delete(t.id),!0)}async function releaseJob(e,t){let n=await e.get(t.id);return!n||n.status!==`running`||n.ownerId!==t.ownerId?!1:(await e.put({...n,leaseExpiresAt:void 0,ownerId:void 0,status:`queued`,updatedAt:t.now}),!0)}async function rescheduleJob(e,t){let n=await e.get(t.id);return!n||n.status!==`running`||n.ownerId!==t.ownerId?!1:(await e.put({...n,availableAt:t.availableAt,failure:t.failure,leaseExpiresAt:void 0,ownerId:void 0,status:`queued`,updatedAt:t.now}),!0)}async function deadLetterJob(e,t){let n=await e.get(t.id);return!n||n.status!==`running`||n.ownerId!==t.ownerId?!1:(await e.put({...n,failure:t.failure,leaseExpiresAt:void 0,ownerId:void 0,status:`dead-letter`,updatedAt:t.now}),!0)}async function renewLeaseJob(e,t){let n=await e.get(t.id);return!n||n.status!==`running`||n.ownerId!==t.ownerId?!1:(await e.put({...n,leaseExpiresAt:t.leaseExpiresAt,updatedAt:t.now}),!0)}async function requeueJob(e,t,n){let r=await e.get(t);if(!r)return{status:`not-found`};if(r.status===`running`)return{status:`running`};if(r.status!==`dead-letter`)return{status:`not-dead-letter`};let i={...r,availableAt:n,failure:void 0,status:`queued`,updatedAt:n};return await e.put(i),{entry:toEntry(i),status:`requeued`}}async function removeJob(e,t){let n=await e.get(t);return n?n.status===`running`?{status:`running`}:(await e.delete(t),{id:t,status:`removed`}):{status:`not-found`}}async function enqueueJob(t,n){if(await t.get(n.id))throw new e.PostmasterJobError(`Postmaster entry "${n.id}" already exists`);await t.put(n)}function toEntry(e){return{attempts:e.attempts,availableAt:e.availableAt,createdAt:e.createdAt,...e.failure?{failure:e.failure}:{},id:e.id,key:e.key,name:e.name,status:e.status,updatedAt:e.updatedAt,version:e.version}}exports.claimJob=claimJob,exports.completeJob=completeJob,exports.deadLetterJob=deadLetterJob,exports.enqueueJob=enqueueJob,exports.releaseJob=releaseJob,exports.removeJob=removeJob,exports.renewLeaseJob=renewLeaseJob,exports.requeueJob=requeueJob,exports.rescheduleJob=rescheduleJob,exports.toEntry=toEntry;
|
|
2
2
|
//# sourceMappingURL=store-ops.cjs.map
|
package/dist/store-ops.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store-ops.cjs","names":[],"sources":["../src/store-ops.ts"],"sourcesContent":["import { PostmasterJobError } from './errors.ts';\nimport type { PostmasterEntry, RemoveResult,
|
|
1
|
+
{"version":3,"file":"store-ops.cjs","names":[],"sources":["../src/store-ops.ts"],"sourcesContent":["import { PostmasterJobError } from './errors.ts';\nimport type { PostmasterEntry, RemoveResult, RequeueResult, StoredFailure, StoredJob, StoreTx } from './types.ts';\n\nexport interface ClaimParams {\n readonly leaseDuration: number;\n readonly now: number;\n readonly ownerId: string;\n}\n\nexport interface OwnedParams {\n readonly id: string;\n readonly now: number;\n readonly ownerId: string;\n}\n\nexport interface RescheduleParams extends OwnedParams {\n readonly availableAt: number;\n readonly failure: StoredFailure;\n}\n\nexport interface DeadLetterParams extends OwnedParams {\n readonly failure: StoredFailure;\n}\n\n/** Claim the earliest eligible job atomically. Returns the claimed entry or undefined. */\nexport async function claimJob(tx: StoreTx, params: ClaimParams): Promise<StoredJob | undefined> {\n const entry = await tx.findClaimable(params.now);\n if (!entry) return undefined;\n const claimed: StoredJob = {\n ...entry,\n attempts: entry.attempts + 1,\n failure: undefined,\n leaseExpiresAt: params.now + params.leaseDuration,\n ownerId: params.ownerId,\n status: 'running',\n updatedAt: params.now,\n };\n await tx.put(claimed);\n return claimed;\n}\n\n/** Complete and delete a job. Returns false if the owner is stale or the job is gone. */\nexport async function completeJob(tx: StoreTx, params: OwnedParams): Promise<boolean> {\n const entry = await tx.get(params.id);\n if (!entry || entry.status !== 'running' || entry.ownerId !== params.ownerId) return false;\n await tx.delete(params.id);\n return true;\n}\n\n/** Release a claimed job back to queued without consuming an attempt. Returns false if stale. */\nexport async function releaseJob(tx: StoreTx, params: OwnedParams): Promise<boolean> {\n const entry = await tx.get(params.id);\n if (!entry || entry.status !== 'running' || entry.ownerId !== params.ownerId) return false;\n await tx.put({\n ...entry,\n leaseExpiresAt: undefined,\n ownerId: undefined,\n status: 'queued',\n updatedAt: params.now,\n });\n return true;\n}\n\n/** Reschedule a running job back to queued with a future availableAt. Returns false if stale. */\nexport async function rescheduleJob(tx: StoreTx, params: RescheduleParams): Promise<boolean> {\n const entry = await tx.get(params.id);\n if (!entry || entry.status !== 'running' || entry.ownerId !== params.ownerId) return false;\n await tx.put({\n ...entry,\n availableAt: params.availableAt,\n failure: params.failure,\n leaseExpiresAt: undefined,\n ownerId: undefined,\n status: 'queued',\n updatedAt: params.now,\n });\n return true;\n}\n\n/** Move a running job to dead-letter. Returns false if stale. */\nexport async function deadLetterJob(tx: StoreTx, params: DeadLetterParams): Promise<boolean> {\n const entry = await tx.get(params.id);\n if (!entry || entry.status !== 'running' || entry.ownerId !== params.ownerId) return false;\n await tx.put({\n ...entry,\n failure: params.failure,\n leaseExpiresAt: undefined,\n ownerId: undefined,\n status: 'dead-letter',\n updatedAt: params.now,\n });\n return true;\n}\n\n/** Renew a lease for the current owner. Returns false if stale. */\nexport async function renewLeaseJob(tx: StoreTx, params: OwnedParams & { leaseExpiresAt: number }): Promise<boolean> {\n const entry = await tx.get(params.id);\n if (!entry || entry.status !== 'running' || entry.ownerId !== params.ownerId) return false;\n await tx.put({ ...entry, leaseExpiresAt: params.leaseExpiresAt, updatedAt: params.now });\n return true;\n}\n\n/** Requeue a dead-letter job back to queued. Returns discriminated result. */\nexport async function requeueJob(tx: StoreTx, id: string, now: number): Promise<RequeueResult> {\n const entry = await tx.get(id);\n if (!entry) return { status: 'not-found' };\n if (entry.status === 'running') return { status: 'running' };\n if (entry.status !== 'dead-letter') return { status: 'not-dead-letter' };\n const requeued: StoredJob = {\n ...entry,\n availableAt: now,\n failure: undefined,\n status: 'queued',\n updatedAt: now,\n };\n await tx.put(requeued);\n return { entry: toEntry(requeued), status: 'requeued' };\n}\n\n/** Remove a queued or dead-letter job. Running jobs cannot be removed. */\nexport async function removeJob(tx: StoreTx, id: string): Promise<RemoveResult> {\n const entry = await tx.get(id);\n if (!entry) return { status: 'not-found' };\n if (entry.status === 'running') return { status: 'running' };\n await tx.delete(id);\n return { id, status: 'removed' };\n}\n\n/** Enqueue a new job. Rejects duplicate ids. */\nexport async function enqueueJob(tx: StoreTx, entry: StoredJob): Promise<void> {\n const existing = await tx.get(entry.id);\n if (existing) throw new PostmasterJobError(`Postmaster entry \"${entry.id}\" already exists`);\n await tx.put(entry);\n}\n\nexport function toEntry(entry: StoredJob): PostmasterEntry {\n return {\n attempts: entry.attempts,\n availableAt: entry.availableAt,\n createdAt: entry.createdAt,\n ...(entry.failure ? { failure: entry.failure } : {}),\n id: entry.id,\n key: entry.key,\n name: entry.name,\n status: entry.status,\n updatedAt: entry.updatedAt,\n version: entry.version,\n };\n}\n"],"mappings":"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"}
|
package/dist/store-ops.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { PostmasterEntry, RemoveResult,
|
|
1
|
+
import type { PostmasterEntry, RemoveResult, RequeueResult, StoredFailure, StoredJob, StoreTx } from './types.ts';
|
|
2
2
|
export interface ClaimParams {
|
|
3
3
|
readonly leaseDuration: number;
|
|
4
4
|
readonly now: number;
|
|
@@ -30,8 +30,8 @@ export declare function deadLetterJob(tx: StoreTx, params: DeadLetterParams): Pr
|
|
|
30
30
|
export declare function renewLeaseJob(tx: StoreTx, params: OwnedParams & {
|
|
31
31
|
leaseExpiresAt: number;
|
|
32
32
|
}): Promise<boolean>;
|
|
33
|
-
/**
|
|
34
|
-
export declare function
|
|
33
|
+
/** Requeue a dead-letter job back to queued. Returns discriminated result. */
|
|
34
|
+
export declare function requeueJob(tx: StoreTx, id: string, now: number): Promise<RequeueResult>;
|
|
35
35
|
/** Remove a queued or dead-letter job. Running jobs cannot be removed. */
|
|
36
36
|
export declare function removeJob(tx: StoreTx, id: string): Promise<RemoveResult>;
|
|
37
37
|
/** Enqueue a new job. Rejects duplicate ids. */
|
package/dist/store-ops.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store-ops.d.ts","sourceRoot":"","sources":["../src/store-ops.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,
|
|
1
|
+
{"version":3,"file":"store-ops.d.ts","sourceRoot":"","sources":["../src/store-ops.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAElH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,gBAAiB,SAAQ,WAAW;IACnD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC;CACjC;AAED,MAAM,WAAW,gBAAiB,SAAQ,WAAW;IACnD,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC;CACjC;AAED,0FAA0F;AAC1F,wBAAsB,QAAQ,CAAC,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,CAc/F;AAED,yFAAyF;AACzF,wBAAsB,WAAW,CAAC,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,CAKpF;AAED,iGAAiG;AACjG,wBAAsB,UAAU,CAAC,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,CAWnF;AAED,iGAAiG;AACjG,wBAAsB,aAAa,CAAC,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC,CAa3F;AAED,iEAAiE;AACjE,wBAAsB,aAAa,CAAC,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC,CAY3F;AAED,mEAAmE;AACnE,wBAAsB,aAAa,CAAC,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,GAAG;IAAE,cAAc,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAKnH;AAED,8EAA8E;AAC9E,wBAAsB,UAAU,CAAC,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAc7F;AAED,0EAA0E;AAC1E,wBAAsB,SAAS,CAAC,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAM9E;AAED,gDAAgD;AAChD,wBAAsB,UAAU,CAAC,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAI7E;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,SAAS,GAAG,eAAe,CAazD"}
|
package/dist/store-ops.js
CHANGED
|
@@ -1,107 +1,2 @@
|
|
|
1
|
-
import
|
|
2
|
-
//#region src/store-ops.ts
|
|
3
|
-
async function t(e, t) {
|
|
4
|
-
let n = await e.findClaimable(t.now);
|
|
5
|
-
if (!n) return;
|
|
6
|
-
let r = {
|
|
7
|
-
...n,
|
|
8
|
-
attempts: n.attempts + 1,
|
|
9
|
-
failure: void 0,
|
|
10
|
-
leaseExpiresAt: t.now + t.leaseDuration,
|
|
11
|
-
ownerId: t.ownerId,
|
|
12
|
-
status: "running",
|
|
13
|
-
updatedAt: t.now
|
|
14
|
-
};
|
|
15
|
-
return await e.put(r), r;
|
|
16
|
-
}
|
|
17
|
-
async function n(e, t) {
|
|
18
|
-
let n = await e.get(t.id);
|
|
19
|
-
return !n || n.status !== "running" || n.ownerId !== t.ownerId ? !1 : (await e.delete(t.id), !0);
|
|
20
|
-
}
|
|
21
|
-
async function r(e, t) {
|
|
22
|
-
let n = await e.get(t.id);
|
|
23
|
-
return !n || n.status !== "running" || n.ownerId !== t.ownerId ? !1 : (await e.put({
|
|
24
|
-
...n,
|
|
25
|
-
leaseExpiresAt: void 0,
|
|
26
|
-
ownerId: void 0,
|
|
27
|
-
status: "queued",
|
|
28
|
-
updatedAt: t.now
|
|
29
|
-
}), !0);
|
|
30
|
-
}
|
|
31
|
-
async function i(e, t) {
|
|
32
|
-
let n = await e.get(t.id);
|
|
33
|
-
return !n || n.status !== "running" || n.ownerId !== t.ownerId ? !1 : (await e.put({
|
|
34
|
-
...n,
|
|
35
|
-
availableAt: t.availableAt,
|
|
36
|
-
failure: t.failure,
|
|
37
|
-
leaseExpiresAt: void 0,
|
|
38
|
-
ownerId: void 0,
|
|
39
|
-
status: "queued",
|
|
40
|
-
updatedAt: t.now
|
|
41
|
-
}), !0);
|
|
42
|
-
}
|
|
43
|
-
async function a(e, t) {
|
|
44
|
-
let n = await e.get(t.id);
|
|
45
|
-
return !n || n.status !== "running" || n.ownerId !== t.ownerId ? !1 : (await e.put({
|
|
46
|
-
...n,
|
|
47
|
-
failure: t.failure,
|
|
48
|
-
leaseExpiresAt: void 0,
|
|
49
|
-
ownerId: void 0,
|
|
50
|
-
status: "dead-letter",
|
|
51
|
-
updatedAt: t.now
|
|
52
|
-
}), !0);
|
|
53
|
-
}
|
|
54
|
-
async function o(e, t) {
|
|
55
|
-
let n = await e.get(t.id);
|
|
56
|
-
return !n || n.status !== "running" || n.ownerId !== t.ownerId ? !1 : (await e.put({
|
|
57
|
-
...n,
|
|
58
|
-
leaseExpiresAt: t.leaseExpiresAt,
|
|
59
|
-
updatedAt: t.now
|
|
60
|
-
}), !0);
|
|
61
|
-
}
|
|
62
|
-
async function s(e, t, n) {
|
|
63
|
-
let r = await e.get(t);
|
|
64
|
-
if (!r) return { status: "not-found" };
|
|
65
|
-
if (r.status === "running") return { status: "running" };
|
|
66
|
-
if (r.status !== "dead-letter") return { status: "not-dead-letter" };
|
|
67
|
-
let i = {
|
|
68
|
-
...r,
|
|
69
|
-
availableAt: n,
|
|
70
|
-
failure: void 0,
|
|
71
|
-
status: "queued",
|
|
72
|
-
updatedAt: n
|
|
73
|
-
};
|
|
74
|
-
return await e.put(i), {
|
|
75
|
-
entry: u(i),
|
|
76
|
-
status: "retried"
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
async function c(e, t) {
|
|
80
|
-
let n = await e.get(t);
|
|
81
|
-
return n ? n.status === "running" ? { status: "running" } : (await e.delete(t), {
|
|
82
|
-
id: t,
|
|
83
|
-
status: "removed"
|
|
84
|
-
}) : { status: "not-found" };
|
|
85
|
-
}
|
|
86
|
-
async function l(t, n) {
|
|
87
|
-
if (await t.get(n.id)) throw new e(`Postmaster entry "${n.id}" already exists`);
|
|
88
|
-
await t.put(n);
|
|
89
|
-
}
|
|
90
|
-
function u(e) {
|
|
91
|
-
return {
|
|
92
|
-
attempts: e.attempts,
|
|
93
|
-
availableAt: e.availableAt,
|
|
94
|
-
createdAt: e.createdAt,
|
|
95
|
-
...e.failure ? { failure: e.failure } : {},
|
|
96
|
-
id: e.id,
|
|
97
|
-
key: e.key,
|
|
98
|
-
name: e.name,
|
|
99
|
-
status: e.status,
|
|
100
|
-
updatedAt: e.updatedAt,
|
|
101
|
-
version: e.version
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
//#endregion
|
|
105
|
-
export { t as claimJob, n as completeJob, a as deadLetterJob, l as enqueueJob, r as releaseJob, c as removeJob, o as renewLeaseJob, i as rescheduleJob, s as retryJob, u as toEntry };
|
|
106
|
-
|
|
1
|
+
import{PostmasterJobError as e}from"./errors.js";async function claimJob(e,t){let n=await e.findClaimable(t.now);if(!n)return;let r={...n,attempts:n.attempts+1,failure:void 0,leaseExpiresAt:t.now+t.leaseDuration,ownerId:t.ownerId,status:`running`,updatedAt:t.now};return await e.put(r),r}async function completeJob(e,t){let n=await e.get(t.id);return!n||n.status!==`running`||n.ownerId!==t.ownerId?!1:(await e.delete(t.id),!0)}async function releaseJob(e,t){let n=await e.get(t.id);return!n||n.status!==`running`||n.ownerId!==t.ownerId?!1:(await e.put({...n,leaseExpiresAt:void 0,ownerId:void 0,status:`queued`,updatedAt:t.now}),!0)}async function rescheduleJob(e,t){let n=await e.get(t.id);return!n||n.status!==`running`||n.ownerId!==t.ownerId?!1:(await e.put({...n,availableAt:t.availableAt,failure:t.failure,leaseExpiresAt:void 0,ownerId:void 0,status:`queued`,updatedAt:t.now}),!0)}async function deadLetterJob(e,t){let n=await e.get(t.id);return!n||n.status!==`running`||n.ownerId!==t.ownerId?!1:(await e.put({...n,failure:t.failure,leaseExpiresAt:void 0,ownerId:void 0,status:`dead-letter`,updatedAt:t.now}),!0)}async function renewLeaseJob(e,t){let n=await e.get(t.id);return!n||n.status!==`running`||n.ownerId!==t.ownerId?!1:(await e.put({...n,leaseExpiresAt:t.leaseExpiresAt,updatedAt:t.now}),!0)}async function requeueJob(e,t,n){let r=await e.get(t);if(!r)return{status:`not-found`};if(r.status===`running`)return{status:`running`};if(r.status!==`dead-letter`)return{status:`not-dead-letter`};let i={...r,availableAt:n,failure:void 0,status:`queued`,updatedAt:n};return await e.put(i),{entry:toEntry(i),status:`requeued`}}async function removeJob(e,t){let n=await e.get(t);return n?n.status===`running`?{status:`running`}:(await e.delete(t),{id:t,status:`removed`}):{status:`not-found`}}async function enqueueJob(t,n){if(await t.get(n.id))throw new e(`Postmaster entry "${n.id}" already exists`);await t.put(n)}function toEntry(e){return{attempts:e.attempts,availableAt:e.availableAt,createdAt:e.createdAt,...e.failure?{failure:e.failure}:{},id:e.id,key:e.key,name:e.name,status:e.status,updatedAt:e.updatedAt,version:e.version}}export{claimJob,completeJob,deadLetterJob,enqueueJob,releaseJob,removeJob,renewLeaseJob,requeueJob,rescheduleJob,toEntry};
|
|
107
2
|
//# sourceMappingURL=store-ops.js.map
|
package/dist/store-ops.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store-ops.js","names":[],"sources":["../src/store-ops.ts"],"sourcesContent":["import { PostmasterJobError } from './errors.ts';\nimport type { PostmasterEntry, RemoveResult,
|
|
1
|
+
{"version":3,"file":"store-ops.js","names":[],"sources":["../src/store-ops.ts"],"sourcesContent":["import { PostmasterJobError } from './errors.ts';\nimport type { PostmasterEntry, RemoveResult, RequeueResult, StoredFailure, StoredJob, StoreTx } from './types.ts';\n\nexport interface ClaimParams {\n readonly leaseDuration: number;\n readonly now: number;\n readonly ownerId: string;\n}\n\nexport interface OwnedParams {\n readonly id: string;\n readonly now: number;\n readonly ownerId: string;\n}\n\nexport interface RescheduleParams extends OwnedParams {\n readonly availableAt: number;\n readonly failure: StoredFailure;\n}\n\nexport interface DeadLetterParams extends OwnedParams {\n readonly failure: StoredFailure;\n}\n\n/** Claim the earliest eligible job atomically. Returns the claimed entry or undefined. */\nexport async function claimJob(tx: StoreTx, params: ClaimParams): Promise<StoredJob | undefined> {\n const entry = await tx.findClaimable(params.now);\n if (!entry) return undefined;\n const claimed: StoredJob = {\n ...entry,\n attempts: entry.attempts + 1,\n failure: undefined,\n leaseExpiresAt: params.now + params.leaseDuration,\n ownerId: params.ownerId,\n status: 'running',\n updatedAt: params.now,\n };\n await tx.put(claimed);\n return claimed;\n}\n\n/** Complete and delete a job. Returns false if the owner is stale or the job is gone. */\nexport async function completeJob(tx: StoreTx, params: OwnedParams): Promise<boolean> {\n const entry = await tx.get(params.id);\n if (!entry || entry.status !== 'running' || entry.ownerId !== params.ownerId) return false;\n await tx.delete(params.id);\n return true;\n}\n\n/** Release a claimed job back to queued without consuming an attempt. Returns false if stale. */\nexport async function releaseJob(tx: StoreTx, params: OwnedParams): Promise<boolean> {\n const entry = await tx.get(params.id);\n if (!entry || entry.status !== 'running' || entry.ownerId !== params.ownerId) return false;\n await tx.put({\n ...entry,\n leaseExpiresAt: undefined,\n ownerId: undefined,\n status: 'queued',\n updatedAt: params.now,\n });\n return true;\n}\n\n/** Reschedule a running job back to queued with a future availableAt. Returns false if stale. */\nexport async function rescheduleJob(tx: StoreTx, params: RescheduleParams): Promise<boolean> {\n const entry = await tx.get(params.id);\n if (!entry || entry.status !== 'running' || entry.ownerId !== params.ownerId) return false;\n await tx.put({\n ...entry,\n availableAt: params.availableAt,\n failure: params.failure,\n leaseExpiresAt: undefined,\n ownerId: undefined,\n status: 'queued',\n updatedAt: params.now,\n });\n return true;\n}\n\n/** Move a running job to dead-letter. Returns false if stale. */\nexport async function deadLetterJob(tx: StoreTx, params: DeadLetterParams): Promise<boolean> {\n const entry = await tx.get(params.id);\n if (!entry || entry.status !== 'running' || entry.ownerId !== params.ownerId) return false;\n await tx.put({\n ...entry,\n failure: params.failure,\n leaseExpiresAt: undefined,\n ownerId: undefined,\n status: 'dead-letter',\n updatedAt: params.now,\n });\n return true;\n}\n\n/** Renew a lease for the current owner. Returns false if stale. */\nexport async function renewLeaseJob(tx: StoreTx, params: OwnedParams & { leaseExpiresAt: number }): Promise<boolean> {\n const entry = await tx.get(params.id);\n if (!entry || entry.status !== 'running' || entry.ownerId !== params.ownerId) return false;\n await tx.put({ ...entry, leaseExpiresAt: params.leaseExpiresAt, updatedAt: params.now });\n return true;\n}\n\n/** Requeue a dead-letter job back to queued. Returns discriminated result. */\nexport async function requeueJob(tx: StoreTx, id: string, now: number): Promise<RequeueResult> {\n const entry = await tx.get(id);\n if (!entry) return { status: 'not-found' };\n if (entry.status === 'running') return { status: 'running' };\n if (entry.status !== 'dead-letter') return { status: 'not-dead-letter' };\n const requeued: StoredJob = {\n ...entry,\n availableAt: now,\n failure: undefined,\n status: 'queued',\n updatedAt: now,\n };\n await tx.put(requeued);\n return { entry: toEntry(requeued), status: 'requeued' };\n}\n\n/** Remove a queued or dead-letter job. Running jobs cannot be removed. */\nexport async function removeJob(tx: StoreTx, id: string): Promise<RemoveResult> {\n const entry = await tx.get(id);\n if (!entry) return { status: 'not-found' };\n if (entry.status === 'running') return { status: 'running' };\n await tx.delete(id);\n return { id, status: 'removed' };\n}\n\n/** Enqueue a new job. Rejects duplicate ids. */\nexport async function enqueueJob(tx: StoreTx, entry: StoredJob): Promise<void> {\n const existing = await tx.get(entry.id);\n if (existing) throw new PostmasterJobError(`Postmaster entry \"${entry.id}\" already exists`);\n await tx.put(entry);\n}\n\nexport function toEntry(entry: StoredJob): PostmasterEntry {\n return {\n attempts: entry.attempts,\n availableAt: entry.availableAt,\n createdAt: entry.createdAt,\n ...(entry.failure ? { failure: entry.failure } : {}),\n id: entry.id,\n key: entry.key,\n name: entry.name,\n status: entry.status,\n updatedAt: entry.updatedAt,\n version: entry.version,\n };\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("../_store-utils.cjs");function
|
|
1
|
+
const e=require("../_store-utils.cjs");function createMemoryPostmasterStore(t=[]){let n=new Map(t.map(t=>[t.id,e.normalize(t)])),r=new AbortController,i=new Set,a=!1,o=Promise.resolve(),exclusive=e=>{let t=o.then(e,e);return o=t.then(()=>void 0,()=>void 0),t},notify=()=>{for(let e of i)e()},live=()=>{if(a)throw Error(`Postmaster store is disposed`)},s={async countByStatus(){let e=0,t=0,r=0;for(let i of n.values())i.status===`dead-letter`?e+=1:i.status===`queued`?t+=1:r+=1;return{deadLetter:e,queued:t,running:r}},async delete(e){n.delete(e)},async findClaimable(t){let r;for(let e of n.values())(e.status===`queued`&&e.availableAt<=t||e.status===`running`&&(e.leaseExpiresAt??0)<=t)&&(!r||e.availableAt<r.availableAt||e.availableAt===r.availableAt&&e.createdAt<r.createdAt)&&(r=e);return r?e.normalize(r):void 0},async findNextWake(e){let t;for(let r of n.values()){let n;r.status===`queued`&&r.availableAt>e?n=r.availableAt:r.status===`running`&&(r.leaseExpiresAt??0)>e&&(n=r.leaseExpiresAt),n!==void 0&&(t===void 0||n<t)&&(t=n)}return t},async get(t){let r=n.get(t);return r?e.normalize(r):void 0},async put(t){n.set(t.id,e.normalize(t))}};return{get disposalSignal(){return r.signal},async dispose(){a||(a=!0,r.abort(),i.clear())},get disposed(){return a},async list(t){return exclusive(()=>(live(),[...n.values()].filter(e=>t?.status===void 0||e.status===t.status).sort((e,t)=>e.createdAt-t.createdAt).map(e.normalize)))},subscribe(e){return live(),i.add(e),()=>i.delete(e)},transact(e){return exclusive(async()=>{live();let t=await e(s);return notify(),t})},async[Symbol.asyncDispose](){await this.dispose()}}}exports.createMemoryPostmasterStore=createMemoryPostmasterStore;
|
|
2
2
|
//# sourceMappingURL=memory-store.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory-store.cjs","names":[],"sources":["../../src/testing/memory-store.ts"],"sourcesContent":["import { normalize } from '../_store-utils.ts';\nimport type { EntryFilter, PostmasterStats, PostmasterStore, StoredJob, StoreTx } from '../types.ts';\n\nexport function createMemoryPostmasterStore(entries: readonly StoredJob[] = []): PostmasterStore {\n const records = new Map(entries.map((entry) => [entry.id, normalize(entry)]));\n const controller = new AbortController();\n const listeners = new Set<() => void>();\n let disposed = false;\n let chain = Promise.resolve();\n\n const exclusive = <T>(fn: () => T | Promise<T>): Promise<T> => {\n const result = chain.then(fn, fn);\n chain = result.then(\n () => undefined,\n () => undefined,\n );\n return result;\n };\n\n const notify = (): void => {\n for (const listener of listeners) listener();\n };\n\n const live = (): void => {\n if (disposed) throw new Error('Postmaster store is disposed');\n };\n\n const tx: StoreTx = {\n async countByStatus(): Promise<PostmasterStats> {\n let deadLetter = 0;\n let queued = 0;\n let running = 0;\n for (const entry of records.values()) {\n if (entry.status === 'dead-letter') deadLetter += 1;\n else if (entry.status === 'queued') queued += 1;\n else running += 1;\n }\n return { deadLetter, queued, running };\n },\n async delete(id: string): Promise<void> {\n records.delete(id);\n },\n async findClaimable(now: number): Promise<StoredJob | undefined> {\n let best: StoredJob | undefined;\n for (const entry of records.values()) {\n const claimable =\n (entry.status === 'queued' && entry.availableAt <= now) ||\n (entry.status === 'running' && (entry.leaseExpiresAt ?? 0) <= now);\n if (!claimable) continue;\n if (\n !best ||\n entry.availableAt < best.availableAt ||\n (entry.availableAt === best.availableAt && entry.createdAt < best.createdAt)\n ) {\n best = entry;\n }\n }\n return best ? normalize(best) : undefined;\n },\n async findNextWake(now: number): Promise<number | undefined> {\n let next: number | undefined;\n for (const entry of records.values()) {\n let wake: number | undefined;\n if (entry.status === 'queued' && entry.availableAt > now) wake = entry.availableAt;\n else if (entry.status === 'running' && (entry.leaseExpiresAt ?? 0) > now) wake = entry.leaseExpiresAt;\n if (wake !== undefined && (next === undefined || wake < next)) next = wake;\n }\n return next;\n },\n async get(id: string): Promise<StoredJob | undefined> {\n const entry = records.get(id);\n return entry ? normalize(entry) : undefined;\n },\n async put(entry: StoredJob): Promise<void> {\n records.set(entry.id, normalize(entry));\n },\n };\n\n return {\n get disposalSignal() {\n return controller.signal;\n },\n async dispose(): Promise<void> {\n if (disposed) return;\n disposed = true;\n controller.abort();\n listeners.clear();\n },\n get disposed() {\n return disposed;\n },\n async list(filter?: EntryFilter): Promise<StoredJob[]> {\n return exclusive(() => {\n live();\n return [...records.values()]\n .filter((entry) => filter?.status === undefined || entry.status === filter.status)\n .sort((a, b) => a.createdAt - b.createdAt)\n .map(normalize);\n });\n },\n subscribe(listener: () => void): () => void {\n live();\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n transact<T>(fn: (tx: StoreTx) => Promise<T>): Promise<T> {\n return exclusive(async () => {\n live();\n const result = await fn(tx);\n notify();\n return result;\n });\n },\n async [Symbol.asyncDispose](): Promise<void> {\n await this.dispose();\n },\n };\n}\n"],"mappings":"uCAGA,SAAgB,
|
|
1
|
+
{"version":3,"file":"memory-store.cjs","names":[],"sources":["../../src/testing/memory-store.ts"],"sourcesContent":["import { normalize } from '../_store-utils.ts';\nimport type { EntryFilter, PostmasterStats, PostmasterStore, StoredJob, StoreTx } from '../types.ts';\n\nexport function createMemoryPostmasterStore(entries: readonly StoredJob[] = []): PostmasterStore {\n const records = new Map(entries.map((entry) => [entry.id, normalize(entry)]));\n const controller = new AbortController();\n const listeners = new Set<() => void>();\n let disposed = false;\n let chain = Promise.resolve();\n\n const exclusive = <T>(fn: () => T | Promise<T>): Promise<T> => {\n const result = chain.then(fn, fn);\n chain = result.then(\n () => undefined,\n () => undefined,\n );\n return result;\n };\n\n const notify = (): void => {\n for (const listener of listeners) listener();\n };\n\n const live = (): void => {\n if (disposed) throw new Error('Postmaster store is disposed');\n };\n\n const tx: StoreTx = {\n async countByStatus(): Promise<PostmasterStats> {\n let deadLetter = 0;\n let queued = 0;\n let running = 0;\n for (const entry of records.values()) {\n if (entry.status === 'dead-letter') deadLetter += 1;\n else if (entry.status === 'queued') queued += 1;\n else running += 1;\n }\n return { deadLetter, queued, running };\n },\n async delete(id: string): Promise<void> {\n records.delete(id);\n },\n async findClaimable(now: number): Promise<StoredJob | undefined> {\n let best: StoredJob | undefined;\n for (const entry of records.values()) {\n const claimable =\n (entry.status === 'queued' && entry.availableAt <= now) ||\n (entry.status === 'running' && (entry.leaseExpiresAt ?? 0) <= now);\n if (!claimable) continue;\n if (\n !best ||\n entry.availableAt < best.availableAt ||\n (entry.availableAt === best.availableAt && entry.createdAt < best.createdAt)\n ) {\n best = entry;\n }\n }\n return best ? normalize(best) : undefined;\n },\n async findNextWake(now: number): Promise<number | undefined> {\n let next: number | undefined;\n for (const entry of records.values()) {\n let wake: number | undefined;\n if (entry.status === 'queued' && entry.availableAt > now) wake = entry.availableAt;\n else if (entry.status === 'running' && (entry.leaseExpiresAt ?? 0) > now) wake = entry.leaseExpiresAt;\n if (wake !== undefined && (next === undefined || wake < next)) next = wake;\n }\n return next;\n },\n async get(id: string): Promise<StoredJob | undefined> {\n const entry = records.get(id);\n return entry ? normalize(entry) : undefined;\n },\n async put(entry: StoredJob): Promise<void> {\n records.set(entry.id, normalize(entry));\n },\n };\n\n return {\n get disposalSignal() {\n return controller.signal;\n },\n async dispose(): Promise<void> {\n if (disposed) return;\n disposed = true;\n controller.abort();\n listeners.clear();\n },\n get disposed() {\n return disposed;\n },\n async list(filter?: EntryFilter): Promise<StoredJob[]> {\n return exclusive(() => {\n live();\n return [...records.values()]\n .filter((entry) => filter?.status === undefined || entry.status === filter.status)\n .sort((a, b) => a.createdAt - b.createdAt)\n .map(normalize);\n });\n },\n subscribe(listener: () => void): () => void {\n live();\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n transact<T>(fn: (tx: StoreTx) => Promise<T>): Promise<T> {\n return exclusive(async () => {\n live();\n const result = await fn(tx);\n notify();\n return result;\n });\n },\n async [Symbol.asyncDispose](): Promise<void> {\n await this.dispose();\n },\n };\n}\n"],"mappings":"uCAGA,SAAgB,4BAA4B,EAAgC,CAAC,EAAoB,CAC/F,IAAM,EAAU,IAAI,IAAI,EAAQ,IAAK,GAAU,CAAC,EAAM,GAAI,EAAA,UAAU,CAAK,CAAC,CAAC,CAAC,EACtE,EAAa,IAAI,gBACjB,EAAY,IAAI,IAClB,EAAW,GACX,EAAQ,QAAQ,QAAQ,EAEtB,UAAgB,GAAyC,CAC7D,IAAM,EAAS,EAAM,KAAK,EAAI,CAAE,EAKhC,MAJA,GAAQ,EAAO,SACP,IAAA,OACA,IAAA,EACR,EACO,CACT,EAEM,WAAqB,CACzB,IAAK,IAAM,KAAY,EAAW,EAAS,CAC7C,EAEM,SAAmB,CACvB,GAAI,EAAU,MAAU,MAAM,8BAA8B,CAC9D,EAEM,EAAc,CAClB,MAAM,eAA0C,CAC9C,IAAI,EAAa,EACb,EAAS,EACT,EAAU,EACd,IAAK,IAAM,KAAS,EAAQ,OAAO,EAC7B,EAAM,SAAW,cAAe,GAAc,EACzC,EAAM,SAAW,SAAU,GAAU,EACzC,GAAW,EAElB,MAAO,CAAE,aAAY,SAAQ,SAAQ,CACvC,EACA,MAAM,OAAO,EAA2B,CACtC,EAAQ,OAAO,CAAE,CACnB,EACA,MAAM,cAAc,EAA6C,CAC/D,IAAI,EACJ,IAAK,IAAM,KAAS,EAAQ,OAAO,GAE9B,EAAM,SAAW,UAAY,EAAM,aAAe,GAClD,EAAM,SAAW,YAAc,EAAM,gBAAkB,IAAM,KAG9D,CAAC,GACD,EAAM,YAAc,EAAK,aACxB,EAAM,cAAgB,EAAK,aAAe,EAAM,UAAY,EAAK,aAElE,EAAO,GAGX,OAAO,EAAO,EAAA,UAAU,CAAI,EAAI,IAAA,EAClC,EACA,MAAM,aAAa,EAA0C,CAC3D,IAAI,EACJ,IAAK,IAAM,KAAS,EAAQ,OAAO,EAAG,CACpC,IAAI,EACA,EAAM,SAAW,UAAY,EAAM,YAAc,EAAK,EAAO,EAAM,YAC9D,EAAM,SAAW,YAAc,EAAM,gBAAkB,GAAK,IAAK,EAAO,EAAM,gBACnF,IAAS,IAAA,KAAc,IAAS,IAAA,IAAa,EAAO,KAAO,EAAO,EACxE,CACA,OAAO,CACT,EACA,MAAM,IAAI,EAA4C,CACpD,IAAM,EAAQ,EAAQ,IAAI,CAAE,EAC5B,OAAO,EAAQ,EAAA,UAAU,CAAK,EAAI,IAAA,EACpC,EACA,MAAM,IAAI,EAAiC,CACzC,EAAQ,IAAI,EAAM,GAAI,EAAA,UAAU,CAAK,CAAC,CACxC,CACF,EAEA,MAAO,CACL,IAAI,gBAAiB,CACnB,OAAO,EAAW,MACpB,EACA,MAAM,SAAyB,CACzB,IACJ,EAAW,GACX,EAAW,MAAM,EACjB,EAAU,MAAM,EAClB,EACA,IAAI,UAAW,CACb,OAAO,CACT,EACA,MAAM,KAAK,EAA4C,CACrD,OAAO,eACL,KAAK,EACE,CAAC,GAAG,EAAQ,OAAO,CAAC,CAAC,CACzB,OAAQ,GAAU,GAAQ,SAAW,IAAA,IAAa,EAAM,SAAW,EAAO,MAAM,CAAC,CACjF,MAAM,EAAG,IAAM,EAAE,UAAY,EAAE,SAAS,CAAC,CACzC,IAAI,EAAA,SAAS,EACjB,CACH,EACA,UAAU,EAAkC,CAG1C,OAFA,KAAK,EACL,EAAU,IAAI,CAAQ,MACT,EAAU,OAAO,CAAQ,CACxC,EACA,SAAY,EAA6C,CACvD,OAAO,UAAU,SAAY,CAC3B,KAAK,EACL,IAAM,EAAS,MAAM,EAAG,CAAE,EAE1B,OADA,OAAO,EACA,CACT,CAAC,CACH,EACA,MAAO,OAAO,eAA+B,CAC3C,MAAM,KAAK,QAAQ,CACrB,CACF,CACF"}
|
|
@@ -1,76 +1,2 @@
|
|
|
1
|
-
import
|
|
2
|
-
//#region src/testing/memory-store.ts
|
|
3
|
-
function t(t = []) {
|
|
4
|
-
let n = new Map(t.map((t) => [t.id, e(t)])), r = new AbortController(), i = /* @__PURE__ */ new Set(), a = !1, o = Promise.resolve(), s = (e) => {
|
|
5
|
-
let t = o.then(e, e);
|
|
6
|
-
return o = t.then(() => void 0, () => void 0), t;
|
|
7
|
-
}, c = () => {
|
|
8
|
-
for (let e of i) e();
|
|
9
|
-
}, l = () => {
|
|
10
|
-
if (a) throw Error("Postmaster store is disposed");
|
|
11
|
-
}, u = {
|
|
12
|
-
async countByStatus() {
|
|
13
|
-
let e = 0, t = 0, r = 0;
|
|
14
|
-
for (let i of n.values()) i.status === "dead-letter" ? e += 1 : i.status === "queued" ? t += 1 : r += 1;
|
|
15
|
-
return {
|
|
16
|
-
deadLetter: e,
|
|
17
|
-
queued: t,
|
|
18
|
-
running: r
|
|
19
|
-
};
|
|
20
|
-
},
|
|
21
|
-
async delete(e) {
|
|
22
|
-
n.delete(e);
|
|
23
|
-
},
|
|
24
|
-
async findClaimable(t) {
|
|
25
|
-
let r;
|
|
26
|
-
for (let e of n.values()) (e.status === "queued" && e.availableAt <= t || e.status === "running" && (e.leaseExpiresAt ?? 0) <= t) && (!r || e.availableAt < r.availableAt || e.availableAt === r.availableAt && e.createdAt < r.createdAt) && (r = e);
|
|
27
|
-
return r ? e(r) : void 0;
|
|
28
|
-
},
|
|
29
|
-
async findNextWake(e) {
|
|
30
|
-
let t;
|
|
31
|
-
for (let r of n.values()) {
|
|
32
|
-
let n;
|
|
33
|
-
r.status === "queued" && r.availableAt > e ? n = r.availableAt : r.status === "running" && (r.leaseExpiresAt ?? 0) > e && (n = r.leaseExpiresAt), n !== void 0 && (t === void 0 || n < t) && (t = n);
|
|
34
|
-
}
|
|
35
|
-
return t;
|
|
36
|
-
},
|
|
37
|
-
async get(t) {
|
|
38
|
-
let r = n.get(t);
|
|
39
|
-
return r ? e(r) : void 0;
|
|
40
|
-
},
|
|
41
|
-
async put(t) {
|
|
42
|
-
n.set(t.id, e(t));
|
|
43
|
-
}
|
|
44
|
-
};
|
|
45
|
-
return {
|
|
46
|
-
get disposalSignal() {
|
|
47
|
-
return r.signal;
|
|
48
|
-
},
|
|
49
|
-
async dispose() {
|
|
50
|
-
a || (a = !0, r.abort(), i.clear());
|
|
51
|
-
},
|
|
52
|
-
get disposed() {
|
|
53
|
-
return a;
|
|
54
|
-
},
|
|
55
|
-
async list(t) {
|
|
56
|
-
return s(() => (l(), [...n.values()].filter((e) => t?.status === void 0 || e.status === t.status).sort((e, t) => e.createdAt - t.createdAt).map(e)));
|
|
57
|
-
},
|
|
58
|
-
subscribe(e) {
|
|
59
|
-
return l(), i.add(e), () => i.delete(e);
|
|
60
|
-
},
|
|
61
|
-
transact(e) {
|
|
62
|
-
return s(async () => {
|
|
63
|
-
l();
|
|
64
|
-
let t = await e(u);
|
|
65
|
-
return c(), t;
|
|
66
|
-
});
|
|
67
|
-
},
|
|
68
|
-
async [Symbol.asyncDispose]() {
|
|
69
|
-
await this.dispose();
|
|
70
|
-
}
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
//#endregion
|
|
74
|
-
export { t as createMemoryPostmasterStore };
|
|
75
|
-
|
|
1
|
+
import{normalize as e}from"../_store-utils.js";function createMemoryPostmasterStore(t=[]){let n=new Map(t.map(t=>[t.id,e(t)])),r=new AbortController,i=new Set,a=!1,o=Promise.resolve(),exclusive=e=>{let t=o.then(e,e);return o=t.then(()=>void 0,()=>void 0),t},notify=()=>{for(let e of i)e()},live=()=>{if(a)throw Error(`Postmaster store is disposed`)},s={async countByStatus(){let e=0,t=0,r=0;for(let i of n.values())i.status===`dead-letter`?e+=1:i.status===`queued`?t+=1:r+=1;return{deadLetter:e,queued:t,running:r}},async delete(e){n.delete(e)},async findClaimable(t){let r;for(let e of n.values())(e.status===`queued`&&e.availableAt<=t||e.status===`running`&&(e.leaseExpiresAt??0)<=t)&&(!r||e.availableAt<r.availableAt||e.availableAt===r.availableAt&&e.createdAt<r.createdAt)&&(r=e);return r?e(r):void 0},async findNextWake(e){let t;for(let r of n.values()){let n;r.status===`queued`&&r.availableAt>e?n=r.availableAt:r.status===`running`&&(r.leaseExpiresAt??0)>e&&(n=r.leaseExpiresAt),n!==void 0&&(t===void 0||n<t)&&(t=n)}return t},async get(t){let r=n.get(t);return r?e(r):void 0},async put(t){n.set(t.id,e(t))}};return{get disposalSignal(){return r.signal},async dispose(){a||(a=!0,r.abort(),i.clear())},get disposed(){return a},async list(t){return exclusive(()=>(live(),[...n.values()].filter(e=>t?.status===void 0||e.status===t.status).sort((e,t)=>e.createdAt-t.createdAt).map(e)))},subscribe(e){return live(),i.add(e),()=>i.delete(e)},transact(e){return exclusive(async()=>{live();let t=await e(s);return notify(),t})},async[Symbol.asyncDispose](){await this.dispose()}}}export{createMemoryPostmasterStore};
|
|
76
2
|
//# sourceMappingURL=memory-store.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory-store.js","names":[],"sources":["../../src/testing/memory-store.ts"],"sourcesContent":["import { normalize } from '../_store-utils.ts';\nimport type { EntryFilter, PostmasterStats, PostmasterStore, StoredJob, StoreTx } from '../types.ts';\n\nexport function createMemoryPostmasterStore(entries: readonly StoredJob[] = []): PostmasterStore {\n const records = new Map(entries.map((entry) => [entry.id, normalize(entry)]));\n const controller = new AbortController();\n const listeners = new Set<() => void>();\n let disposed = false;\n let chain = Promise.resolve();\n\n const exclusive = <T>(fn: () => T | Promise<T>): Promise<T> => {\n const result = chain.then(fn, fn);\n chain = result.then(\n () => undefined,\n () => undefined,\n );\n return result;\n };\n\n const notify = (): void => {\n for (const listener of listeners) listener();\n };\n\n const live = (): void => {\n if (disposed) throw new Error('Postmaster store is disposed');\n };\n\n const tx: StoreTx = {\n async countByStatus(): Promise<PostmasterStats> {\n let deadLetter = 0;\n let queued = 0;\n let running = 0;\n for (const entry of records.values()) {\n if (entry.status === 'dead-letter') deadLetter += 1;\n else if (entry.status === 'queued') queued += 1;\n else running += 1;\n }\n return { deadLetter, queued, running };\n },\n async delete(id: string): Promise<void> {\n records.delete(id);\n },\n async findClaimable(now: number): Promise<StoredJob | undefined> {\n let best: StoredJob | undefined;\n for (const entry of records.values()) {\n const claimable =\n (entry.status === 'queued' && entry.availableAt <= now) ||\n (entry.status === 'running' && (entry.leaseExpiresAt ?? 0) <= now);\n if (!claimable) continue;\n if (\n !best ||\n entry.availableAt < best.availableAt ||\n (entry.availableAt === best.availableAt && entry.createdAt < best.createdAt)\n ) {\n best = entry;\n }\n }\n return best ? normalize(best) : undefined;\n },\n async findNextWake(now: number): Promise<number | undefined> {\n let next: number | undefined;\n for (const entry of records.values()) {\n let wake: number | undefined;\n if (entry.status === 'queued' && entry.availableAt > now) wake = entry.availableAt;\n else if (entry.status === 'running' && (entry.leaseExpiresAt ?? 0) > now) wake = entry.leaseExpiresAt;\n if (wake !== undefined && (next === undefined || wake < next)) next = wake;\n }\n return next;\n },\n async get(id: string): Promise<StoredJob | undefined> {\n const entry = records.get(id);\n return entry ? normalize(entry) : undefined;\n },\n async put(entry: StoredJob): Promise<void> {\n records.set(entry.id, normalize(entry));\n },\n };\n\n return {\n get disposalSignal() {\n return controller.signal;\n },\n async dispose(): Promise<void> {\n if (disposed) return;\n disposed = true;\n controller.abort();\n listeners.clear();\n },\n get disposed() {\n return disposed;\n },\n async list(filter?: EntryFilter): Promise<StoredJob[]> {\n return exclusive(() => {\n live();\n return [...records.values()]\n .filter((entry) => filter?.status === undefined || entry.status === filter.status)\n .sort((a, b) => a.createdAt - b.createdAt)\n .map(normalize);\n });\n },\n subscribe(listener: () => void): () => void {\n live();\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n transact<T>(fn: (tx: StoreTx) => Promise<T>): Promise<T> {\n return exclusive(async () => {\n live();\n const result = await fn(tx);\n notify();\n return result;\n });\n },\n async [Symbol.asyncDispose](): Promise<void> {\n await this.dispose();\n },\n };\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"memory-store.js","names":[],"sources":["../../src/testing/memory-store.ts"],"sourcesContent":["import { normalize } from '../_store-utils.ts';\nimport type { EntryFilter, PostmasterStats, PostmasterStore, StoredJob, StoreTx } from '../types.ts';\n\nexport function createMemoryPostmasterStore(entries: readonly StoredJob[] = []): PostmasterStore {\n const records = new Map(entries.map((entry) => [entry.id, normalize(entry)]));\n const controller = new AbortController();\n const listeners = new Set<() => void>();\n let disposed = false;\n let chain = Promise.resolve();\n\n const exclusive = <T>(fn: () => T | Promise<T>): Promise<T> => {\n const result = chain.then(fn, fn);\n chain = result.then(\n () => undefined,\n () => undefined,\n );\n return result;\n };\n\n const notify = (): void => {\n for (const listener of listeners) listener();\n };\n\n const live = (): void => {\n if (disposed) throw new Error('Postmaster store is disposed');\n };\n\n const tx: StoreTx = {\n async countByStatus(): Promise<PostmasterStats> {\n let deadLetter = 0;\n let queued = 0;\n let running = 0;\n for (const entry of records.values()) {\n if (entry.status === 'dead-letter') deadLetter += 1;\n else if (entry.status === 'queued') queued += 1;\n else running += 1;\n }\n return { deadLetter, queued, running };\n },\n async delete(id: string): Promise<void> {\n records.delete(id);\n },\n async findClaimable(now: number): Promise<StoredJob | undefined> {\n let best: StoredJob | undefined;\n for (const entry of records.values()) {\n const claimable =\n (entry.status === 'queued' && entry.availableAt <= now) ||\n (entry.status === 'running' && (entry.leaseExpiresAt ?? 0) <= now);\n if (!claimable) continue;\n if (\n !best ||\n entry.availableAt < best.availableAt ||\n (entry.availableAt === best.availableAt && entry.createdAt < best.createdAt)\n ) {\n best = entry;\n }\n }\n return best ? normalize(best) : undefined;\n },\n async findNextWake(now: number): Promise<number | undefined> {\n let next: number | undefined;\n for (const entry of records.values()) {\n let wake: number | undefined;\n if (entry.status === 'queued' && entry.availableAt > now) wake = entry.availableAt;\n else if (entry.status === 'running' && (entry.leaseExpiresAt ?? 0) > now) wake = entry.leaseExpiresAt;\n if (wake !== undefined && (next === undefined || wake < next)) next = wake;\n }\n return next;\n },\n async get(id: string): Promise<StoredJob | undefined> {\n const entry = records.get(id);\n return entry ? normalize(entry) : undefined;\n },\n async put(entry: StoredJob): Promise<void> {\n records.set(entry.id, normalize(entry));\n },\n };\n\n return {\n get disposalSignal() {\n return controller.signal;\n },\n async dispose(): Promise<void> {\n if (disposed) return;\n disposed = true;\n controller.abort();\n listeners.clear();\n },\n get disposed() {\n return disposed;\n },\n async list(filter?: EntryFilter): Promise<StoredJob[]> {\n return exclusive(() => {\n live();\n return [...records.values()]\n .filter((entry) => filter?.status === undefined || entry.status === filter.status)\n .sort((a, b) => a.createdAt - b.createdAt)\n .map(normalize);\n });\n },\n subscribe(listener: () => void): () => void {\n live();\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n transact<T>(fn: (tx: StoreTx) => Promise<T>): Promise<T> {\n return exclusive(async () => {\n live();\n const result = await fn(tx);\n notify();\n return result;\n });\n },\n async [Symbol.asyncDispose](): Promise<void> {\n await this.dispose();\n },\n };\n}\n"],"mappings":"+CAGA,SAAgB,4BAA4B,EAAgC,CAAC,EAAoB,CAC/F,IAAM,EAAU,IAAI,IAAI,EAAQ,IAAK,GAAU,CAAC,EAAM,GAAI,EAAU,CAAK,CAAC,CAAC,CAAC,EACtE,EAAa,IAAI,gBACjB,EAAY,IAAI,IAClB,EAAW,GACX,EAAQ,QAAQ,QAAQ,EAEtB,UAAgB,GAAyC,CAC7D,IAAM,EAAS,EAAM,KAAK,EAAI,CAAE,EAKhC,MAJA,GAAQ,EAAO,SACP,IAAA,OACA,IAAA,EACR,EACO,CACT,EAEM,WAAqB,CACzB,IAAK,IAAM,KAAY,EAAW,EAAS,CAC7C,EAEM,SAAmB,CACvB,GAAI,EAAU,MAAU,MAAM,8BAA8B,CAC9D,EAEM,EAAc,CAClB,MAAM,eAA0C,CAC9C,IAAI,EAAa,EACb,EAAS,EACT,EAAU,EACd,IAAK,IAAM,KAAS,EAAQ,OAAO,EAC7B,EAAM,SAAW,cAAe,GAAc,EACzC,EAAM,SAAW,SAAU,GAAU,EACzC,GAAW,EAElB,MAAO,CAAE,aAAY,SAAQ,SAAQ,CACvC,EACA,MAAM,OAAO,EAA2B,CACtC,EAAQ,OAAO,CAAE,CACnB,EACA,MAAM,cAAc,EAA6C,CAC/D,IAAI,EACJ,IAAK,IAAM,KAAS,EAAQ,OAAO,GAE9B,EAAM,SAAW,UAAY,EAAM,aAAe,GAClD,EAAM,SAAW,YAAc,EAAM,gBAAkB,IAAM,KAG9D,CAAC,GACD,EAAM,YAAc,EAAK,aACxB,EAAM,cAAgB,EAAK,aAAe,EAAM,UAAY,EAAK,aAElE,EAAO,GAGX,OAAO,EAAO,EAAU,CAAI,EAAI,IAAA,EAClC,EACA,MAAM,aAAa,EAA0C,CAC3D,IAAI,EACJ,IAAK,IAAM,KAAS,EAAQ,OAAO,EAAG,CACpC,IAAI,EACA,EAAM,SAAW,UAAY,EAAM,YAAc,EAAK,EAAO,EAAM,YAC9D,EAAM,SAAW,YAAc,EAAM,gBAAkB,GAAK,IAAK,EAAO,EAAM,gBACnF,IAAS,IAAA,KAAc,IAAS,IAAA,IAAa,EAAO,KAAO,EAAO,EACxE,CACA,OAAO,CACT,EACA,MAAM,IAAI,EAA4C,CACpD,IAAM,EAAQ,EAAQ,IAAI,CAAE,EAC5B,OAAO,EAAQ,EAAU,CAAK,EAAI,IAAA,EACpC,EACA,MAAM,IAAI,EAAiC,CACzC,EAAQ,IAAI,EAAM,GAAI,EAAU,CAAK,CAAC,CACxC,CACF,EAEA,MAAO,CACL,IAAI,gBAAiB,CACnB,OAAO,EAAW,MACpB,EACA,MAAM,SAAyB,CACzB,IACJ,EAAW,GACX,EAAW,MAAM,EACjB,EAAU,MAAM,EAClB,EACA,IAAI,UAAW,CACb,OAAO,CACT,EACA,MAAM,KAAK,EAA4C,CACrD,OAAO,eACL,KAAK,EACE,CAAC,GAAG,EAAQ,OAAO,CAAC,CAAC,CACzB,OAAQ,GAAU,GAAQ,SAAW,IAAA,IAAa,EAAM,SAAW,EAAO,MAAM,CAAC,CACjF,MAAM,EAAG,IAAM,EAAE,UAAY,EAAE,SAAS,CAAC,CACzC,IAAI,CAAS,EACjB,CACH,EACA,UAAU,EAAkC,CAG1C,OAFA,KAAK,EACL,EAAU,IAAI,CAAQ,MACT,EAAU,OAAO,CAAQ,CACxC,EACA,SAAY,EAA6C,CACvD,OAAO,UAAU,SAAY,CAC3B,KAAK,EACL,IAAM,EAAS,MAAM,EAAG,CAAE,EAE1B,OADA,OAAO,EACA,CACT,CAAC,CACH,EACA,MAAO,OAAO,eAA+B,CAC3C,MAAM,KAAK,QAAQ,CACrB,CACF,CACF"}
|
package/dist/testing.js
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
import
|
|
2
|
-
export { e as createMemoryPostmasterStore };
|
|
1
|
+
import{createMemoryPostmasterStore as e}from"./testing/memory-store.js";export{e as createMemoryPostmasterStore};
|