217 lines
5.6 KiB
TypeScript
217 lines
5.6 KiB
TypeScript
export type JsonPrimitive = string | number | boolean | null;
|
|
export type JsonValue = JsonPrimitive | JsonValue[] | { [key: string]: JsonValue };
|
|
export type Awaitable<T> = T | Promise<T>;
|
|
export type JobData = Record<string, JsonValue>;
|
|
export type JobStatus =
|
|
| 'pending'
|
|
| 'active'
|
|
| 'completed'
|
|
| 'failed'
|
|
| 'cancelled'
|
|
| 'stale';
|
|
export type JobPhaseStatus = 'pending' | 'active' | 'completed' | 'failed' | 'cancelled';
|
|
export type RetryBackoffStrategy = 'fixed' | 'linear' | 'exponential';
|
|
export type ErrorDisposition = 'recoverable' | 'fatal';
|
|
|
|
export interface JobPhaseState {
|
|
name: string;
|
|
status: JobPhaseStatus;
|
|
progress: number;
|
|
message: string | null;
|
|
startedAt: string | null;
|
|
completedAt: string | null;
|
|
error: string | null;
|
|
}
|
|
|
|
export interface JobFailure {
|
|
message: string;
|
|
phase: string | null;
|
|
recoverable: boolean;
|
|
timestamp: string;
|
|
attempt: number;
|
|
}
|
|
|
|
export interface JobRetryEvent {
|
|
jobId: string;
|
|
phase: string | null;
|
|
attempt: number;
|
|
delayMs: number;
|
|
nextRunAt: string;
|
|
timestamp: string;
|
|
}
|
|
|
|
export interface JobProgressEvent {
|
|
jobId: string;
|
|
phase: string;
|
|
phaseProgress: number;
|
|
overallProgress: number;
|
|
message: string | null;
|
|
timestamp: string;
|
|
details?: JsonValue;
|
|
}
|
|
|
|
export interface JobRecord<TData extends JobData = JobData> {
|
|
id: string;
|
|
status: JobStatus;
|
|
data: TData;
|
|
currentPhase: string | null;
|
|
phases: JobPhaseState[];
|
|
phaseResults: Record<string, JsonValue | undefined>;
|
|
progress: number;
|
|
progressMessage: string | null;
|
|
error: JobFailure | null;
|
|
retryCount: number;
|
|
maxAttempts: number;
|
|
webhookUrl: string | null;
|
|
webhookSent: boolean;
|
|
createdAt: string;
|
|
startedAt: string | null;
|
|
completedAt: string | null;
|
|
updatedAt: string;
|
|
scheduledAt: string | null;
|
|
cancelledAt: string | null;
|
|
}
|
|
|
|
export interface EnqueueOptions {
|
|
id?: string;
|
|
scheduledAt?: string | Date;
|
|
maxAttempts?: number;
|
|
webhookUrl?: string;
|
|
}
|
|
|
|
export interface RetryOptions {
|
|
fromStart?: boolean;
|
|
scheduledAt?: string | Date;
|
|
}
|
|
|
|
export interface ListJobsOptions {
|
|
statuses?: JobStatus[];
|
|
limit?: number;
|
|
offset?: number;
|
|
}
|
|
|
|
export interface StreamOptions {
|
|
jobId?: string;
|
|
includeSnapshot?: boolean;
|
|
keepAliveMs?: number;
|
|
}
|
|
|
|
export interface RetryConfig<TData extends JobData = JobData> {
|
|
maxAttempts?: number;
|
|
strategy?: RetryBackoffStrategy;
|
|
baseDelayMs?: number;
|
|
maxDelayMs?: number;
|
|
classifyError?: (
|
|
error: unknown,
|
|
job: JobRecord<TData>,
|
|
) => Awaitable<ErrorDisposition>;
|
|
}
|
|
|
|
export interface RetentionConfig<TData extends JobData = JobData> {
|
|
staleAfterMs: number;
|
|
deleteAfterMs: number;
|
|
intervalMs?: number;
|
|
onStale?: (job: JobRecord<TData>) => Awaitable<void>;
|
|
onDelete?: (job: JobRecord<TData>) => Awaitable<void>;
|
|
}
|
|
|
|
export type WebhookEventName =
|
|
| 'job:completed'
|
|
| 'job:failed'
|
|
| 'job:retrying'
|
|
| 'job:cancelled'
|
|
| 'job:stale';
|
|
|
|
export interface WebhookConfig {
|
|
url?: string;
|
|
events?: WebhookEventName[];
|
|
secret?: string;
|
|
timeoutMs?: number;
|
|
headers?: Record<string, string>;
|
|
maxAttempts?: number;
|
|
baseDelayMs?: number;
|
|
maxDelayMs?: number;
|
|
}
|
|
|
|
export interface QueueConfig<TData extends JobData = JobData> {
|
|
dbPath: string;
|
|
phases: readonly string[];
|
|
concurrency?: number;
|
|
retry?: RetryConfig<TData>;
|
|
retention?: RetentionConfig<TData>;
|
|
webhook?: WebhookConfig;
|
|
shutdownTimeoutMs?: number;
|
|
}
|
|
|
|
export interface PhaseContext<TData extends JobData = JobData> {
|
|
readonly job: JobRecord<TData>;
|
|
readonly phase: string;
|
|
readonly signal: AbortSignal;
|
|
progress: (percent: number, message?: string, details?: JsonValue) => Promise<JobRecord<TData>>;
|
|
phaseResult: <TResult extends JsonValue = JsonValue>(phaseName: string) => TResult | undefined;
|
|
phaseResults: () => Record<string, JsonValue | undefined>;
|
|
isCancelled: () => boolean;
|
|
throwIfCancelled: () => Promise<void>;
|
|
}
|
|
|
|
export type PhaseHandler<TData extends JobData = JobData> = (
|
|
job: JobRecord<TData>,
|
|
context: PhaseContext<TData>,
|
|
) => Awaitable<JsonValue | undefined>;
|
|
|
|
export interface WebhookDispatchResult {
|
|
event: WebhookEventName;
|
|
jobId: string;
|
|
status: number;
|
|
deliveredAt: string;
|
|
}
|
|
|
|
export interface WebhookDispatchError {
|
|
event: WebhookEventName;
|
|
jobId: string;
|
|
message: string;
|
|
finalAttempt: number;
|
|
}
|
|
|
|
export interface QueueStreamEvent<TData extends JobData = JobData> {
|
|
type:
|
|
| 'snapshot'
|
|
| 'job:enqueued'
|
|
| 'job:started'
|
|
| 'job:progress'
|
|
| 'job:phase:completed'
|
|
| 'job:completed'
|
|
| 'job:failed'
|
|
| 'job:retrying'
|
|
| 'job:cancelled'
|
|
| 'job:stale'
|
|
| 'job:deleted'
|
|
| 'job:webhook:delivered'
|
|
| 'job:webhook:failed'
|
|
| 'ping';
|
|
jobId?: string;
|
|
job?: JobRecord<TData>;
|
|
progress?: JobProgressEvent;
|
|
phase?: JobPhaseState;
|
|
failure?: JobFailure;
|
|
retry?: JobRetryEvent;
|
|
webhook?: WebhookDispatchResult | WebhookDispatchError;
|
|
deletedJobId?: string;
|
|
timestamp: string;
|
|
}
|
|
|
|
export interface JobQueueEvents<TData extends JobData = JobData> {
|
|
'job:enqueued': [job: JobRecord<TData>];
|
|
'job:started': [job: JobRecord<TData>];
|
|
'job:progress': [job: JobRecord<TData>, progress: JobProgressEvent];
|
|
'job:phase:completed': [job: JobRecord<TData>, phase: JobPhaseState];
|
|
'job:completed': [job: JobRecord<TData>];
|
|
'job:failed': [job: JobRecord<TData>, failure: JobFailure];
|
|
'job:retrying': [job: JobRecord<TData>, retry: JobRetryEvent];
|
|
'job:cancelled': [job: JobRecord<TData>];
|
|
'job:stale': [job: JobRecord<TData>];
|
|
'job:deleted': [jobId: string];
|
|
'job:webhook:delivered': [job: JobRecord<TData>, result: WebhookDispatchResult];
|
|
'job:webhook:failed': [job: JobRecord<TData>, error: WebhookDispatchError];
|
|
}
|