@monque/core 1.1.0 → 1.1.2
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/LICENSE +15 -0
- package/dist/CHANGELOG.md +89 -0
- package/dist/LICENSE +15 -0
- package/dist/README.md +150 -0
- package/dist/index.cjs +6 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -14
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +6 -14
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +6 -6
- package/dist/index.mjs.map +1 -1
- package/package.json +9 -7
- package/src/events/index.ts +1 -0
- package/src/events/types.ts +113 -0
- package/src/index.ts +51 -0
- package/src/jobs/guards.ts +220 -0
- package/src/jobs/index.ts +29 -0
- package/src/jobs/types.ts +335 -0
- package/src/scheduler/helpers.ts +107 -0
- package/src/scheduler/index.ts +5 -0
- package/src/scheduler/monque.ts +1309 -0
- package/src/scheduler/services/change-stream-handler.ts +239 -0
- package/src/scheduler/services/index.ts +8 -0
- package/src/scheduler/services/job-manager.ts +455 -0
- package/src/scheduler/services/job-processor.ts +301 -0
- package/src/scheduler/services/job-query.ts +411 -0
- package/src/scheduler/services/job-scheduler.ts +267 -0
- package/src/scheduler/services/types.ts +48 -0
- package/src/scheduler/types.ts +123 -0
- package/src/shared/errors.ts +225 -0
- package/src/shared/index.ts +18 -0
- package/src/shared/utils/backoff.ts +77 -0
- package/src/shared/utils/cron.ts +67 -0
- package/src/shared/utils/index.ts +7 -0
- package/src/workers/index.ts +1 -0
- package/src/workers/types.ts +39 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@monque/core",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"description": "MongoDB-backed job scheduler with atomic locking, exponential backoff, and cron scheduling",
|
|
5
5
|
"author": "Maurice de Bruyn <debruyn.maurice@gmail.com>",
|
|
6
6
|
"repository": {
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
"url": "git+https://github.com/ueberBrot/monque.git",
|
|
9
9
|
"directory": "packages/core"
|
|
10
10
|
},
|
|
11
|
+
"license": "ISC",
|
|
11
12
|
"bugs": {
|
|
12
13
|
"url": "https://github.com/ueberBrot/monque/issues"
|
|
13
14
|
},
|
|
@@ -36,7 +37,8 @@
|
|
|
36
37
|
}
|
|
37
38
|
},
|
|
38
39
|
"files": [
|
|
39
|
-
"dist"
|
|
40
|
+
"dist",
|
|
41
|
+
"src"
|
|
40
42
|
],
|
|
41
43
|
"scripts": {
|
|
42
44
|
"build": "tsdown",
|
|
@@ -66,7 +68,6 @@
|
|
|
66
68
|
"atomic",
|
|
67
69
|
"persistence"
|
|
68
70
|
],
|
|
69
|
-
"license": "ISC",
|
|
70
71
|
"dependencies": {
|
|
71
72
|
"cron-parser": "^5.5.0"
|
|
72
73
|
},
|
|
@@ -79,12 +80,13 @@
|
|
|
79
80
|
"@testcontainers/mongodb": "^11.11.0",
|
|
80
81
|
"@total-typescript/ts-reset": "^0.6.1",
|
|
81
82
|
"@types/bun": "^1.3.6",
|
|
82
|
-
"@vitest/coverage-v8": "^4.0.
|
|
83
|
+
"@vitest/coverage-v8": "^4.0.18",
|
|
83
84
|
"fishery": "^2.4.0",
|
|
84
85
|
"mongodb": "^7.0.0",
|
|
85
|
-
"publint": "^0.3.
|
|
86
|
-
"tsdown": "^0.
|
|
86
|
+
"publint": "^0.3.17",
|
|
87
|
+
"tsdown": "^0.20.1",
|
|
87
88
|
"typescript": "^5.9.3",
|
|
88
|
-
"
|
|
89
|
+
"unplugin-unused": "^0.5.7",
|
|
90
|
+
"vitest": "^4.0.18"
|
|
89
91
|
}
|
|
90
92
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type { MonqueEventMap } from './types.js';
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import type { Job } from '@/jobs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Event payloads for Monque lifecycle events.
|
|
5
|
+
*/
|
|
6
|
+
export interface MonqueEventMap {
|
|
7
|
+
/**
|
|
8
|
+
* Emitted when a job begins processing.
|
|
9
|
+
*/
|
|
10
|
+
'job:start': Job;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Emitted when a job finishes successfully.
|
|
14
|
+
*/
|
|
15
|
+
'job:complete': {
|
|
16
|
+
job: Job;
|
|
17
|
+
/** Processing duration in milliseconds */
|
|
18
|
+
duration: number;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Emitted when a job fails (may retry).
|
|
23
|
+
*/
|
|
24
|
+
'job:fail': {
|
|
25
|
+
job: Job;
|
|
26
|
+
error: Error;
|
|
27
|
+
/** Whether the job will be retried */
|
|
28
|
+
willRetry: boolean;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Emitted for unexpected errors during processing.
|
|
33
|
+
*/
|
|
34
|
+
'job:error': {
|
|
35
|
+
error: Error;
|
|
36
|
+
job?: Job;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Emitted when stale jobs are recovered on startup.
|
|
41
|
+
*/
|
|
42
|
+
'stale:recovered': {
|
|
43
|
+
count: number;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Emitted when the change stream is successfully connected.
|
|
48
|
+
*/
|
|
49
|
+
'changestream:connected': undefined;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Emitted when a change stream error occurs.
|
|
53
|
+
*/
|
|
54
|
+
'changestream:error': {
|
|
55
|
+
error: Error;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Emitted when the change stream is closed.
|
|
60
|
+
*/
|
|
61
|
+
'changestream:closed': undefined;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Emitted when falling back from change streams to polling-only mode.
|
|
65
|
+
*/
|
|
66
|
+
'changestream:fallback': {
|
|
67
|
+
reason: string;
|
|
68
|
+
};
|
|
69
|
+
/**
|
|
70
|
+
* Emitted when a job is manually cancelled.
|
|
71
|
+
*/
|
|
72
|
+
'job:cancelled': {
|
|
73
|
+
job: Job;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Emitted when a job is manually retried.
|
|
78
|
+
*/
|
|
79
|
+
'job:retried': {
|
|
80
|
+
job: Job;
|
|
81
|
+
previousStatus: 'failed' | 'cancelled';
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Emitted when a job is manually deleted.
|
|
86
|
+
*/
|
|
87
|
+
'job:deleted': {
|
|
88
|
+
jobId: string;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Emitted when multiple jobs are cancelled in bulk.
|
|
93
|
+
*/
|
|
94
|
+
'jobs:cancelled': {
|
|
95
|
+
jobIds: string[];
|
|
96
|
+
count: number;
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Emitted when multiple jobs are retried in bulk.
|
|
101
|
+
*/
|
|
102
|
+
'jobs:retried': {
|
|
103
|
+
jobIds: string[];
|
|
104
|
+
count: number;
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Emitted when multiple jobs are deleted in bulk.
|
|
109
|
+
*/
|
|
110
|
+
'jobs:deleted': {
|
|
111
|
+
count: number;
|
|
112
|
+
};
|
|
113
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// Types - Events
|
|
2
|
+
export type { MonqueEventMap } from '@/events';
|
|
3
|
+
// Types - Jobs
|
|
4
|
+
export {
|
|
5
|
+
type BulkOperationResult,
|
|
6
|
+
CursorDirection,
|
|
7
|
+
type CursorOptions,
|
|
8
|
+
type CursorPage,
|
|
9
|
+
type EnqueueOptions,
|
|
10
|
+
type GetJobsFilter,
|
|
11
|
+
isCancelledJob,
|
|
12
|
+
isCompletedJob,
|
|
13
|
+
isFailedJob,
|
|
14
|
+
isPendingJob,
|
|
15
|
+
isPersistedJob,
|
|
16
|
+
isProcessingJob,
|
|
17
|
+
isRecurringJob,
|
|
18
|
+
isValidJobStatus,
|
|
19
|
+
type Job,
|
|
20
|
+
type JobHandler,
|
|
21
|
+
type JobSelector,
|
|
22
|
+
JobStatus,
|
|
23
|
+
type JobStatusType,
|
|
24
|
+
type PersistedJob,
|
|
25
|
+
type QueueStats,
|
|
26
|
+
type ScheduleOptions,
|
|
27
|
+
} from '@/jobs';
|
|
28
|
+
// Types - Scheduler
|
|
29
|
+
export type { MonqueOptions } from '@/scheduler';
|
|
30
|
+
// Main class
|
|
31
|
+
export { Monque } from '@/scheduler';
|
|
32
|
+
// Errors
|
|
33
|
+
// Utilities (for advanced use cases)
|
|
34
|
+
export {
|
|
35
|
+
AggregationTimeoutError,
|
|
36
|
+
ConnectionError,
|
|
37
|
+
calculateBackoff,
|
|
38
|
+
calculateBackoffDelay,
|
|
39
|
+
DEFAULT_BASE_INTERVAL,
|
|
40
|
+
DEFAULT_MAX_BACKOFF_DELAY,
|
|
41
|
+
getNextCronDate,
|
|
42
|
+
InvalidCronError,
|
|
43
|
+
InvalidCursorError,
|
|
44
|
+
JobStateError,
|
|
45
|
+
MonqueError,
|
|
46
|
+
ShutdownTimeoutError,
|
|
47
|
+
validateCronExpression,
|
|
48
|
+
WorkerRegistrationError,
|
|
49
|
+
} from '@/shared';
|
|
50
|
+
// Types - Workers
|
|
51
|
+
export type { WorkerOptions } from '@/workers';
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import type { Job, JobStatusType, PersistedJob } from './types.js';
|
|
2
|
+
import { JobStatus } from './types.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Type guard to check if a job has been persisted to MongoDB.
|
|
6
|
+
*
|
|
7
|
+
* A persisted job is guaranteed to have an `_id` field, which means it has been
|
|
8
|
+
* successfully inserted into the database. This is useful when you need to ensure
|
|
9
|
+
* a job can be updated or referenced by its ID.
|
|
10
|
+
*
|
|
11
|
+
* @template T - The type of the job's data payload
|
|
12
|
+
* @param job - The job to check
|
|
13
|
+
* @returns `true` if the job has a valid `_id`, narrowing the type to `PersistedJob<T>`
|
|
14
|
+
*
|
|
15
|
+
* @example Basic usage
|
|
16
|
+
* ```typescript
|
|
17
|
+
* const job: Job<EmailData> = await monque.enqueue('send-email', emailData);
|
|
18
|
+
*
|
|
19
|
+
* if (isPersistedJob(job)) {
|
|
20
|
+
* // TypeScript knows job._id exists
|
|
21
|
+
* console.log(`Job ID: ${job._id.toString()}`);
|
|
22
|
+
* }
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* @example In a conditional
|
|
26
|
+
* ```typescript
|
|
27
|
+
* function logJobId(job: Job) {
|
|
28
|
+
* if (!isPersistedJob(job)) {
|
|
29
|
+
* console.log('Job not yet persisted');
|
|
30
|
+
* return;
|
|
31
|
+
* }
|
|
32
|
+
* // TypeScript knows job is PersistedJob here
|
|
33
|
+
* console.log(`Processing job ${job._id.toString()}`);
|
|
34
|
+
* }
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export function isPersistedJob<T>(job: Job<T>): job is PersistedJob<T> {
|
|
38
|
+
return '_id' in job && job._id !== undefined && job._id !== null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Type guard to check if a value is a valid job status.
|
|
43
|
+
*
|
|
44
|
+
* Validates that a value is one of the five valid job statuses: `'pending'`,
|
|
45
|
+
* `'processing'`, `'completed'`, `'failed'`, or `'cancelled'`. Useful for runtime validation
|
|
46
|
+
* of user input or external data.
|
|
47
|
+
*
|
|
48
|
+
* @param value - The value to check
|
|
49
|
+
* @returns `true` if the value is a valid `JobStatusType`, narrowing the type
|
|
50
|
+
*
|
|
51
|
+
* @example Validating user input
|
|
52
|
+
* ```typescript
|
|
53
|
+
* function filterByStatus(status: string) {
|
|
54
|
+
* if (!isValidJobStatus(status)) {
|
|
55
|
+
* throw new Error(`Invalid status: ${status}`);
|
|
56
|
+
* }
|
|
57
|
+
* // TypeScript knows status is JobStatusType here
|
|
58
|
+
* return db.jobs.find({ status });
|
|
59
|
+
* }
|
|
60
|
+
* ```
|
|
61
|
+
*
|
|
62
|
+
* @example Runtime validation
|
|
63
|
+
* ```typescript
|
|
64
|
+
* const statusFromApi = externalData.status;
|
|
65
|
+
*
|
|
66
|
+
* if (isValidJobStatus(statusFromApi)) {
|
|
67
|
+
* job.status = statusFromApi;
|
|
68
|
+
* } else {
|
|
69
|
+
* job.status = JobStatus.PENDING;
|
|
70
|
+
* }
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
export function isValidJobStatus(value: unknown): value is JobStatusType {
|
|
74
|
+
return typeof value === 'string' && Object.values(JobStatus).includes(value as JobStatusType);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Type guard to check if a job is in pending status.
|
|
79
|
+
*
|
|
80
|
+
* A convenience helper for checking if a job is waiting to be processed.
|
|
81
|
+
* Equivalent to `job.status === JobStatus.PENDING` but with better semantics.
|
|
82
|
+
*
|
|
83
|
+
* @template T - The type of the job's data payload
|
|
84
|
+
* @param job - The job to check
|
|
85
|
+
* @returns `true` if the job status is `'pending'`
|
|
86
|
+
*
|
|
87
|
+
* @example Filter pending jobs
|
|
88
|
+
* ```typescript
|
|
89
|
+
* const jobs = await monque.getJobs();
|
|
90
|
+
* const pendingJobs = jobs.filter(isPendingJob);
|
|
91
|
+
* console.log(`${pendingJobs.length} jobs waiting to be processed`);
|
|
92
|
+
* ```
|
|
93
|
+
*
|
|
94
|
+
* @example Conditional logic
|
|
95
|
+
* ```typescript
|
|
96
|
+
* if (isPendingJob(job)) {
|
|
97
|
+
* await monque.now(job.name, job.data);
|
|
98
|
+
* }
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
101
|
+
export function isPendingJob<T>(job: Job<T>): boolean {
|
|
102
|
+
return job.status === JobStatus.PENDING;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Type guard to check if a job is currently being processed.
|
|
107
|
+
*
|
|
108
|
+
* A convenience helper for checking if a job is actively running.
|
|
109
|
+
* Equivalent to `job.status === JobStatus.PROCESSING` but with better semantics.
|
|
110
|
+
*
|
|
111
|
+
* @template T - The type of the job's data payload
|
|
112
|
+
* @param job - The job to check
|
|
113
|
+
* @returns `true` if the job status is `'processing'`
|
|
114
|
+
*
|
|
115
|
+
* @example Monitor active jobs
|
|
116
|
+
* ```typescript
|
|
117
|
+
* const jobs = await monque.getJobs();
|
|
118
|
+
* const activeJobs = jobs.filter(isProcessingJob);
|
|
119
|
+
* console.log(`${activeJobs.length} jobs currently running`);
|
|
120
|
+
* ```
|
|
121
|
+
*/
|
|
122
|
+
export function isProcessingJob<T>(job: Job<T>): boolean {
|
|
123
|
+
return job.status === JobStatus.PROCESSING;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Type guard to check if a job has completed successfully.
|
|
128
|
+
*
|
|
129
|
+
* A convenience helper for checking if a job finished without errors.
|
|
130
|
+
* Equivalent to `job.status === JobStatus.COMPLETED` but with better semantics.
|
|
131
|
+
*
|
|
132
|
+
* @template T - The type of the job's data payload
|
|
133
|
+
* @param job - The job to check
|
|
134
|
+
* @returns `true` if the job status is `'completed'`
|
|
135
|
+
*
|
|
136
|
+
* @example Find completed jobs
|
|
137
|
+
* ```typescript
|
|
138
|
+
* const jobs = await monque.getJobs();
|
|
139
|
+
* const completedJobs = jobs.filter(isCompletedJob);
|
|
140
|
+
* console.log(`${completedJobs.length} jobs completed successfully`);
|
|
141
|
+
* ```
|
|
142
|
+
*/
|
|
143
|
+
export function isCompletedJob<T>(job: Job<T>): boolean {
|
|
144
|
+
return job.status === JobStatus.COMPLETED;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Type guard to check if a job has permanently failed.
|
|
149
|
+
*
|
|
150
|
+
* A convenience helper for checking if a job exhausted all retries.
|
|
151
|
+
* Equivalent to `job.status === JobStatus.FAILED` but with better semantics.
|
|
152
|
+
*
|
|
153
|
+
* @template T - The type of the job's data payload
|
|
154
|
+
* @param job - The job to check
|
|
155
|
+
* @returns `true` if the job status is `'failed'`
|
|
156
|
+
*
|
|
157
|
+
* @example Handle failed jobs
|
|
158
|
+
* ```typescript
|
|
159
|
+
* const jobs = await monque.getJobs();
|
|
160
|
+
* const failedJobs = jobs.filter(isFailedJob);
|
|
161
|
+
*
|
|
162
|
+
* for (const job of failedJobs) {
|
|
163
|
+
* console.error(`Job ${job.name} failed: ${job.failReason}`);
|
|
164
|
+
* await sendAlert(job);
|
|
165
|
+
* }
|
|
166
|
+
* ```
|
|
167
|
+
*/
|
|
168
|
+
export function isFailedJob<T>(job: Job<T>): boolean {
|
|
169
|
+
return job.status === JobStatus.FAILED;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Type guard to check if a job has been manually cancelled.
|
|
174
|
+
*
|
|
175
|
+
* A convenience helper for checking if a job was cancelled by an operator.
|
|
176
|
+
* Equivalent to `job.status === JobStatus.CANCELLED` but with better semantics.
|
|
177
|
+
*
|
|
178
|
+
* @template T - The type of the job's data payload
|
|
179
|
+
* @param job - The job to check
|
|
180
|
+
* @returns `true` if the job status is `'cancelled'`
|
|
181
|
+
*
|
|
182
|
+
* @example Filter cancelled jobs
|
|
183
|
+
* ```typescript
|
|
184
|
+
* const jobs = await monque.getJobs();
|
|
185
|
+
* const cancelledJobs = jobs.filter(isCancelledJob);
|
|
186
|
+
* console.log(`${cancelledJobs.length} jobs were cancelled`);
|
|
187
|
+
* ```
|
|
188
|
+
*/
|
|
189
|
+
export function isCancelledJob<T>(job: Job<T>): boolean {
|
|
190
|
+
return job.status === JobStatus.CANCELLED;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Type guard to check if a job is a recurring scheduled job.
|
|
195
|
+
*
|
|
196
|
+
* A recurring job has a `repeatInterval` cron expression and will be automatically
|
|
197
|
+
* rescheduled after each successful completion.
|
|
198
|
+
*
|
|
199
|
+
* @template T - The type of the job's data payload
|
|
200
|
+
* @param job - The job to check
|
|
201
|
+
* @returns `true` if the job has a `repeatInterval` defined
|
|
202
|
+
*
|
|
203
|
+
* @example Filter recurring jobs
|
|
204
|
+
* ```typescript
|
|
205
|
+
* const jobs = await monque.getJobs();
|
|
206
|
+
* const recurringJobs = jobs.filter(isRecurringJob);
|
|
207
|
+
* console.log(`${recurringJobs.length} jobs will repeat automatically`);
|
|
208
|
+
* ```
|
|
209
|
+
*
|
|
210
|
+
* @example Conditional cleanup
|
|
211
|
+
* ```typescript
|
|
212
|
+
* if (!isRecurringJob(job) && isCompletedJob(job)) {
|
|
213
|
+
* // Safe to delete one-time completed jobs
|
|
214
|
+
* await deleteJob(job._id);
|
|
215
|
+
* }
|
|
216
|
+
* ```
|
|
217
|
+
*/
|
|
218
|
+
export function isRecurringJob<T>(job: Job<T>): boolean {
|
|
219
|
+
return job.repeatInterval !== undefined && job.repeatInterval !== null;
|
|
220
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// Guards
|
|
2
|
+
export {
|
|
3
|
+
isCancelledJob,
|
|
4
|
+
isCompletedJob,
|
|
5
|
+
isFailedJob,
|
|
6
|
+
isPendingJob,
|
|
7
|
+
isPersistedJob,
|
|
8
|
+
isProcessingJob,
|
|
9
|
+
isRecurringJob,
|
|
10
|
+
isValidJobStatus,
|
|
11
|
+
} from './guards.js';
|
|
12
|
+
// Types
|
|
13
|
+
export {
|
|
14
|
+
type BulkOperationResult,
|
|
15
|
+
CursorDirection,
|
|
16
|
+
type CursorDirectionType,
|
|
17
|
+
type CursorOptions,
|
|
18
|
+
type CursorPage,
|
|
19
|
+
type EnqueueOptions,
|
|
20
|
+
type GetJobsFilter,
|
|
21
|
+
type Job,
|
|
22
|
+
type JobHandler,
|
|
23
|
+
type JobSelector,
|
|
24
|
+
JobStatus,
|
|
25
|
+
type JobStatusType,
|
|
26
|
+
type PersistedJob,
|
|
27
|
+
type QueueStats,
|
|
28
|
+
type ScheduleOptions,
|
|
29
|
+
} from './types.js';
|