@nicnocquee/dataqueue 1.20.0 → 1.22.0
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/cli.cjs +6 -0
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +6 -0
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +185 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +48 -4
- package/dist/index.d.ts +48 -4
- package/dist/index.js +181 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/cli.ts +6 -0
- package/src/db-util.test.ts +56 -1
- package/src/db-util.ts +77 -6
- package/src/index.ts +19 -1
- package/src/queue.test.ts +449 -0
- package/src/queue.ts +147 -3
- package/src/types.ts +33 -3
package/src/queue.ts
CHANGED
|
@@ -421,7 +421,7 @@ export const cancelAllUpcomingJobs = async (
|
|
|
421
421
|
filters?: {
|
|
422
422
|
jobType?: string;
|
|
423
423
|
priority?: number;
|
|
424
|
-
runAt?: Date;
|
|
424
|
+
runAt?: Date | { gt?: Date; gte?: Date; lt?: Date; lte?: Date; eq?: Date };
|
|
425
425
|
tags?: { values: string[]; mode?: TagQueryMode };
|
|
426
426
|
},
|
|
427
427
|
): Promise<number> => {
|
|
@@ -443,8 +443,32 @@ export const cancelAllUpcomingJobs = async (
|
|
|
443
443
|
params.push(filters.priority);
|
|
444
444
|
}
|
|
445
445
|
if (filters.runAt) {
|
|
446
|
-
|
|
447
|
-
|
|
446
|
+
if (filters.runAt instanceof Date) {
|
|
447
|
+
query += ` AND run_at = $${paramIdx++}`;
|
|
448
|
+
params.push(filters.runAt);
|
|
449
|
+
} else if (typeof filters.runAt === 'object') {
|
|
450
|
+
const ops = filters.runAt;
|
|
451
|
+
if (ops.gt) {
|
|
452
|
+
query += ` AND run_at > $${paramIdx++}`;
|
|
453
|
+
params.push(ops.gt);
|
|
454
|
+
}
|
|
455
|
+
if (ops.gte) {
|
|
456
|
+
query += ` AND run_at >= $${paramIdx++}`;
|
|
457
|
+
params.push(ops.gte);
|
|
458
|
+
}
|
|
459
|
+
if (ops.lt) {
|
|
460
|
+
query += ` AND run_at < $${paramIdx++}`;
|
|
461
|
+
params.push(ops.lt);
|
|
462
|
+
}
|
|
463
|
+
if (ops.lte) {
|
|
464
|
+
query += ` AND run_at <= $${paramIdx++}`;
|
|
465
|
+
params.push(ops.lte);
|
|
466
|
+
}
|
|
467
|
+
if (ops.eq) {
|
|
468
|
+
query += ` AND run_at = $${paramIdx++}`;
|
|
469
|
+
params.push(ops.eq);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
448
472
|
}
|
|
449
473
|
if (
|
|
450
474
|
filters.tags &&
|
|
@@ -661,3 +685,123 @@ export const getJobsByTags = async <
|
|
|
661
685
|
client.release();
|
|
662
686
|
}
|
|
663
687
|
};
|
|
688
|
+
|
|
689
|
+
export const getJobs = async <PayloadMap, T extends keyof PayloadMap & string>(
|
|
690
|
+
pool: Pool,
|
|
691
|
+
filters?: {
|
|
692
|
+
jobType?: string;
|
|
693
|
+
priority?: number;
|
|
694
|
+
runAt?: Date | { gt?: Date; gte?: Date; lt?: Date; lte?: Date; eq?: Date };
|
|
695
|
+
tags?: { values: string[]; mode?: TagQueryMode };
|
|
696
|
+
},
|
|
697
|
+
limit = 100,
|
|
698
|
+
offset = 0,
|
|
699
|
+
): Promise<JobRecord<PayloadMap, T>[]> => {
|
|
700
|
+
const client = await pool.connect();
|
|
701
|
+
try {
|
|
702
|
+
let query = `SELECT id, job_type AS "jobType", payload, status, max_attempts AS "maxAttempts", attempts, priority, run_at AS "runAt", timeout_ms AS "timeoutMs", created_at AS "createdAt", updated_at AS "updatedAt", started_at AS "startedAt", completed_at AS "completedAt", last_failed_at AS "lastFailedAt", locked_at AS "lockedAt", locked_by AS "lockedBy", error_history AS "errorHistory", failure_reason AS "failureReason", next_attempt_at AS "nextAttemptAt", last_failed_at AS "lastFailedAt", last_retried_at AS "lastRetriedAt", last_cancelled_at AS "lastCancelledAt", pending_reason AS "pendingReason", tags FROM job_queue`;
|
|
703
|
+
const params: any[] = [];
|
|
704
|
+
let where: string[] = [];
|
|
705
|
+
let paramIdx = 1;
|
|
706
|
+
if (filters) {
|
|
707
|
+
if (filters.jobType) {
|
|
708
|
+
where.push(`job_type = $${paramIdx++}`);
|
|
709
|
+
params.push(filters.jobType);
|
|
710
|
+
}
|
|
711
|
+
if (filters.priority !== undefined) {
|
|
712
|
+
where.push(`priority = $${paramIdx++}`);
|
|
713
|
+
params.push(filters.priority);
|
|
714
|
+
}
|
|
715
|
+
if (filters.runAt) {
|
|
716
|
+
if (filters.runAt instanceof Date) {
|
|
717
|
+
where.push(`run_at = $${paramIdx++}`);
|
|
718
|
+
params.push(filters.runAt);
|
|
719
|
+
} else if (
|
|
720
|
+
typeof filters.runAt === 'object' &&
|
|
721
|
+
(filters.runAt.gt !== undefined ||
|
|
722
|
+
filters.runAt.gte !== undefined ||
|
|
723
|
+
filters.runAt.lt !== undefined ||
|
|
724
|
+
filters.runAt.lte !== undefined ||
|
|
725
|
+
filters.runAt.eq !== undefined)
|
|
726
|
+
) {
|
|
727
|
+
const ops = filters.runAt as {
|
|
728
|
+
gt?: Date;
|
|
729
|
+
gte?: Date;
|
|
730
|
+
lt?: Date;
|
|
731
|
+
lte?: Date;
|
|
732
|
+
eq?: Date;
|
|
733
|
+
};
|
|
734
|
+
if (ops.gt) {
|
|
735
|
+
where.push(`run_at > $${paramIdx++}`);
|
|
736
|
+
params.push(ops.gt);
|
|
737
|
+
}
|
|
738
|
+
if (ops.gte) {
|
|
739
|
+
where.push(`run_at >= $${paramIdx++}`);
|
|
740
|
+
params.push(ops.gte);
|
|
741
|
+
}
|
|
742
|
+
if (ops.lt) {
|
|
743
|
+
where.push(`run_at < $${paramIdx++}`);
|
|
744
|
+
params.push(ops.lt);
|
|
745
|
+
}
|
|
746
|
+
if (ops.lte) {
|
|
747
|
+
where.push(`run_at <= $${paramIdx++}`);
|
|
748
|
+
params.push(ops.lte);
|
|
749
|
+
}
|
|
750
|
+
if (ops.eq) {
|
|
751
|
+
where.push(`run_at = $${paramIdx++}`);
|
|
752
|
+
params.push(ops.eq);
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
if (
|
|
757
|
+
filters.tags &&
|
|
758
|
+
filters.tags.values &&
|
|
759
|
+
filters.tags.values.length > 0
|
|
760
|
+
) {
|
|
761
|
+
const mode = filters.tags.mode || 'all';
|
|
762
|
+
const tagValues = filters.tags.values;
|
|
763
|
+
switch (mode) {
|
|
764
|
+
case 'exact':
|
|
765
|
+
where.push(`tags = $${paramIdx++}`);
|
|
766
|
+
params.push(tagValues);
|
|
767
|
+
break;
|
|
768
|
+
case 'all':
|
|
769
|
+
where.push(`tags @> $${paramIdx++}`);
|
|
770
|
+
params.push(tagValues);
|
|
771
|
+
break;
|
|
772
|
+
case 'any':
|
|
773
|
+
where.push(`tags && $${paramIdx++}`);
|
|
774
|
+
params.push(tagValues);
|
|
775
|
+
break;
|
|
776
|
+
case 'none':
|
|
777
|
+
where.push(`NOT (tags && $${paramIdx++})`);
|
|
778
|
+
params.push(tagValues);
|
|
779
|
+
break;
|
|
780
|
+
default:
|
|
781
|
+
where.push(`tags @> $${paramIdx++}`);
|
|
782
|
+
params.push(tagValues);
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
if (where.length > 0) {
|
|
787
|
+
query += ` WHERE ${where.join(' AND ')}`;
|
|
788
|
+
}
|
|
789
|
+
// Always add LIMIT and OFFSET as the last parameters
|
|
790
|
+
paramIdx = params.length + 1;
|
|
791
|
+
query += ` ORDER BY created_at DESC LIMIT $${paramIdx++} OFFSET $${paramIdx}`;
|
|
792
|
+
params.push(limit, offset);
|
|
793
|
+
const result = await client.query(query, params);
|
|
794
|
+
log(`Found ${result.rows.length} jobs`);
|
|
795
|
+
return result.rows.map((job) => ({
|
|
796
|
+
...job,
|
|
797
|
+
payload: job.payload,
|
|
798
|
+
timeoutMs: job.timeoutMs,
|
|
799
|
+
failureReason: job.failureReason,
|
|
800
|
+
}));
|
|
801
|
+
} catch (error) {
|
|
802
|
+
log(`Error getting jobs: ${error}`);
|
|
803
|
+
throw error;
|
|
804
|
+
} finally {
|
|
805
|
+
client.release();
|
|
806
|
+
}
|
|
807
|
+
};
|
package/src/types.ts
CHANGED
|
@@ -164,6 +164,25 @@ export interface Processor {
|
|
|
164
164
|
start: () => Promise<number>;
|
|
165
165
|
}
|
|
166
166
|
|
|
167
|
+
export interface DatabaseSSLConfig {
|
|
168
|
+
/**
|
|
169
|
+
* CA certificate as PEM string or file path. If the value starts with 'file://', it will be loaded from file, otherwise treated as PEM string.
|
|
170
|
+
*/
|
|
171
|
+
ca?: string;
|
|
172
|
+
/**
|
|
173
|
+
* Client certificate as PEM string or file path. If the value starts with 'file://', it will be loaded from file, otherwise treated as PEM string.
|
|
174
|
+
*/
|
|
175
|
+
cert?: string;
|
|
176
|
+
/**
|
|
177
|
+
* Client private key as PEM string or file path. If the value starts with 'file://', it will be loaded from file, otherwise treated as PEM string.
|
|
178
|
+
*/
|
|
179
|
+
key?: string;
|
|
180
|
+
/**
|
|
181
|
+
* Whether to reject unauthorized certificates (default: true)
|
|
182
|
+
*/
|
|
183
|
+
rejectUnauthorized?: boolean;
|
|
184
|
+
}
|
|
185
|
+
|
|
167
186
|
export interface JobQueueConfig {
|
|
168
187
|
databaseConfig: {
|
|
169
188
|
connectionString?: string;
|
|
@@ -172,7 +191,7 @@ export interface JobQueueConfig {
|
|
|
172
191
|
database?: string;
|
|
173
192
|
user?: string;
|
|
174
193
|
password?: string;
|
|
175
|
-
ssl?:
|
|
194
|
+
ssl?: DatabaseSSLConfig;
|
|
176
195
|
};
|
|
177
196
|
verbose?: boolean;
|
|
178
197
|
}
|
|
@@ -225,6 +244,17 @@ export interface JobQueue<PayloadMap> {
|
|
|
225
244
|
limit?: number,
|
|
226
245
|
offset?: number,
|
|
227
246
|
) => Promise<JobRecord<PayloadMap, T>[]>;
|
|
247
|
+
/**
|
|
248
|
+
* Get jobs by filters.
|
|
249
|
+
/**
|
|
250
|
+
* Get jobs by filters.
|
|
251
|
+
*/
|
|
252
|
+
getJobs: <T extends JobType<PayloadMap>>(filters?: {
|
|
253
|
+
jobType?: string;
|
|
254
|
+
priority?: number;
|
|
255
|
+
runAt?: Date | { gt?: Date; gte?: Date; lt?: Date; lte?: Date; eq?: Date };
|
|
256
|
+
tags?: { values: string[]; mode?: TagQueryMode };
|
|
257
|
+
}) => Promise<JobRecord<PayloadMap, T>[]>;
|
|
228
258
|
/**
|
|
229
259
|
* Retry a job given its ID.
|
|
230
260
|
* - This will set the job status back to 'pending', clear the locked_at and locked_by, and allow it to be picked up by other workers.
|
|
@@ -253,13 +283,13 @@ export interface JobQueue<PayloadMap> {
|
|
|
253
283
|
* - The filters are:
|
|
254
284
|
* - jobType: The job type to cancel.
|
|
255
285
|
* - priority: The priority of the job to cancel.
|
|
256
|
-
* - runAt: The time the job is scheduled to run at.
|
|
286
|
+
* - runAt: The time the job is scheduled to run at (now supports gt/gte/lt/lte/eq).
|
|
257
287
|
* - tags: An object with 'values' (string[]) and 'mode' (TagQueryMode) for tag-based cancellation.
|
|
258
288
|
*/
|
|
259
289
|
cancelAllUpcomingJobs: (filters?: {
|
|
260
290
|
jobType?: string;
|
|
261
291
|
priority?: number;
|
|
262
|
-
runAt?: Date;
|
|
292
|
+
runAt?: Date | { gt?: Date; gte?: Date; lt?: Date; lte?: Date; eq?: Date };
|
|
263
293
|
tags?: { values: string[]; mode?: TagQueryMode };
|
|
264
294
|
}) => Promise<number>;
|
|
265
295
|
/**
|