bunqueue 2.8.34 → 2.8.36
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/README.md +14 -2
- package/dist/application/backgroundTasks.js +37 -7
- package/dist/application/contextFactory.js +5 -0
- package/dist/application/dlqManager.d.ts +6 -0
- package/dist/application/dlqManager.js +35 -14
- package/dist/application/lockManager.js +22 -8
- package/dist/application/operations/customId.d.ts +31 -0
- package/dist/application/operations/customId.js +59 -0
- package/dist/application/operations/jobClaim.d.ts +17 -0
- package/dist/application/operations/jobClaim.js +20 -0
- package/dist/application/operations/jobManagement.d.ts +4 -5
- package/dist/application/operations/jobManagement.js +15 -116
- package/dist/application/operations/jobMoveOperations.d.ts +9 -0
- package/dist/application/operations/jobMoveOperations.js +94 -0
- package/dist/application/operations/jobStateTransitions.js +3 -0
- package/dist/application/operations/pull.js +5 -0
- package/dist/application/operations/push.js +8 -103
- package/dist/application/operations/pushInsert.d.ts +12 -0
- package/dist/application/operations/pushInsert.js +25 -0
- package/dist/application/operations/pushLocks.d.ts +14 -0
- package/dist/application/operations/pushLocks.js +43 -0
- package/dist/application/operations/queueControl.d.ts +1 -1
- package/dist/application/operations/queueControl.js +1 -1
- package/dist/application/queueManager.d.ts +2 -2
- package/dist/application/queueManager.js +30 -10
- package/dist/application/stallDetection.js +17 -8
- package/dist/client/queue/dlq.d.ts +23 -1
- package/dist/client/queue/dlq.js +75 -0
- package/dist/client/queue/helpers.js +2 -0
- package/dist/client/queue/jobProxy.d.ts +1 -1
- package/dist/client/queue/operations/control.d.ts +17 -0
- package/dist/client/queue/operations/control.js +41 -0
- package/dist/client/queue/operations/counts.d.ts +1 -0
- package/dist/client/queue/operations/counts.js +3 -0
- package/dist/client/queue/queue.d.ts +13 -0
- package/dist/client/queue/queue.js +39 -0
- package/dist/client/queue/rateLimit.d.ts +18 -3
- package/dist/client/queue/rateLimit.js +45 -10
- package/dist/client/queue/stall.d.ts +2 -0
- package/dist/client/queue/stall.js +12 -0
- package/dist/domain/queue/dependencyTracker.d.ts +5 -0
- package/dist/domain/queue/dependencyTracker.js +20 -0
- package/dist/domain/queue/limiterManager.d.ts +14 -2
- package/dist/domain/queue/limiterManager.js +32 -5
- package/dist/domain/queue/shard.d.ts +3 -2
- package/dist/domain/queue/shard.js +11 -2
- package/dist/domain/types/command.d.ts +4 -0
- package/dist/domain/types/queue.d.ts +4 -0
- package/dist/domain/types/queue.js +2 -0
- package/dist/infrastructure/persistence/schema.d.ts +2 -2
- package/dist/infrastructure/persistence/schema.js +38 -2
- package/dist/infrastructure/persistence/sqlite.d.ts +20 -1
- package/dist/infrastructure/persistence/sqlite.js +62 -6
- package/dist/infrastructure/persistence/sqliteBatch.js +8 -6
- package/dist/infrastructure/persistence/sqliteSerializer.d.ts +6 -0
- package/dist/infrastructure/persistence/sqliteSerializer.js +9 -1
- package/dist/infrastructure/persistence/statements.d.ts +8 -1
- package/dist/infrastructure/persistence/statements.js +7 -5
- package/dist/infrastructure/scheduler/cronScheduler.d.ts +5 -0
- package/dist/infrastructure/scheduler/cronScheduler.js +39 -13
- package/dist/infrastructure/server/handlers/advanced.js +11 -2
- package/dist/infrastructure/server/httpRouteQueueConfig.js +2 -0
- package/package.json +4 -1
package/dist/client/queue/dlq.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { getSharedManager } from '../manager';
|
|
6
6
|
import { jobId } from '../../domain/types/job';
|
|
7
|
+
import { createSimpleJob } from './jobProxy';
|
|
7
8
|
import * as dlqOps from './dlqOps';
|
|
8
9
|
/** Client-side cache for TCP mode */
|
|
9
10
|
const tcpDlqConfigCache = new Map();
|
|
@@ -18,6 +19,18 @@ export function setDlqConfig(ctx, config) {
|
|
|
18
19
|
void ctx.tcp.send({ cmd: 'SetDlqConfig', queue: ctx.name, config });
|
|
19
20
|
}
|
|
20
21
|
}
|
|
22
|
+
/** Set DLQ configuration and resolve once the server has applied it. */
|
|
23
|
+
export async function setDlqConfigAsync(ctx, config) {
|
|
24
|
+
if (ctx.embedded) {
|
|
25
|
+
dlqOps.setDlqConfig(ctx.name, config);
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
if (!ctx.tcp)
|
|
29
|
+
return;
|
|
30
|
+
const current = tcpDlqConfigCache.get(ctx.name) ?? {};
|
|
31
|
+
tcpDlqConfigCache.set(ctx.name, { ...current, ...config });
|
|
32
|
+
await ctx.tcp.send({ cmd: 'SetDlqConfig', queue: ctx.name, config });
|
|
33
|
+
}
|
|
21
34
|
/** Get DLQ configuration */
|
|
22
35
|
export function getDlqConfig(ctx) {
|
|
23
36
|
if (ctx.embedded)
|
|
@@ -45,6 +58,38 @@ export function getDlq(ctx, filter) {
|
|
|
45
58
|
return [];
|
|
46
59
|
return dlqOps.getDlqEntries(ctx.name, filter);
|
|
47
60
|
}
|
|
61
|
+
/**
|
|
62
|
+
* Get the dead jobs in the DLQ, working over TCP too (wire command `Dlq`).
|
|
63
|
+
* Returns public Job objects; the wire does not carry DlqEntry metadata
|
|
64
|
+
* (reason, enteredAt, attempts) — that stays embedded-only via getDlq().
|
|
65
|
+
*/
|
|
66
|
+
export async function getDlqJobsAsync(ctx, count) {
|
|
67
|
+
let raw;
|
|
68
|
+
if (ctx.embedded) {
|
|
69
|
+
raw = getSharedManager().getDlq(ctx.name, count);
|
|
70
|
+
}
|
|
71
|
+
else if (ctx.tcp) {
|
|
72
|
+
const response = await ctx.tcp.send({ cmd: 'Dlq', queue: ctx.name, count });
|
|
73
|
+
if (!response.ok)
|
|
74
|
+
return [];
|
|
75
|
+
raw = (response.jobs ?? []);
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
return [];
|
|
79
|
+
}
|
|
80
|
+
return raw.map((job) => {
|
|
81
|
+
const name = job.data?.name ?? 'unknown';
|
|
82
|
+
return createSimpleJob(String(job.id), name, job.data, job.createdAt ?? Date.now(), {
|
|
83
|
+
queueName: ctx.name,
|
|
84
|
+
embedded: ctx.embedded,
|
|
85
|
+
tcp: ctx.tcp,
|
|
86
|
+
getJobState: ctx.getJobState,
|
|
87
|
+
removeAsync: ctx.removeAsync,
|
|
88
|
+
retryJob: ctx.retryJob,
|
|
89
|
+
getChildrenValues: ctx.getChildrenValues,
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
}
|
|
48
93
|
/** Get DLQ stats */
|
|
49
94
|
export function getDlqStats(ctx) {
|
|
50
95
|
if (!ctx.embedded) {
|
|
@@ -67,6 +112,21 @@ export function retryDlq(ctx, id) {
|
|
|
67
112
|
void ctx.tcp.send({ cmd: 'RetryDlq', queue: ctx.name, jobId: id });
|
|
68
113
|
return 0;
|
|
69
114
|
}
|
|
115
|
+
/**
|
|
116
|
+
* Retry DLQ entries and resolve with the retried count once the server has
|
|
117
|
+
* processed it. The fire-and-forget retryDlq() always returns 0 over TCP and
|
|
118
|
+
* discards the server's count.
|
|
119
|
+
*/
|
|
120
|
+
export async function retryDlqAsync(ctx, id) {
|
|
121
|
+
if (ctx.embedded)
|
|
122
|
+
return dlqOps.retryDlqEmbedded(ctx.name, id);
|
|
123
|
+
if (!ctx.tcp)
|
|
124
|
+
return 0;
|
|
125
|
+
const response = await ctx.tcp.send({ cmd: 'RetryDlq', queue: ctx.name, jobId: id });
|
|
126
|
+
if (!response.ok)
|
|
127
|
+
return 0;
|
|
128
|
+
return (response.count ?? 0);
|
|
129
|
+
}
|
|
70
130
|
/** Retry DLQ entries by filter */
|
|
71
131
|
export function retryDlqByFilter(ctx, filter) {
|
|
72
132
|
if (!ctx.embedded)
|
|
@@ -81,6 +141,21 @@ export function purgeDlq(ctx) {
|
|
|
81
141
|
void ctx.tcp.send({ cmd: 'PurgeDlq', queue: ctx.name });
|
|
82
142
|
return 0;
|
|
83
143
|
}
|
|
144
|
+
/**
|
|
145
|
+
* Purge the DLQ and resolve with the purged count once the server has
|
|
146
|
+
* processed it. The fire-and-forget purgeDlq() always returns 0 over TCP;
|
|
147
|
+
* purge-then-assert-empty patterns need this variant.
|
|
148
|
+
*/
|
|
149
|
+
export async function purgeDlqAsync(ctx) {
|
|
150
|
+
if (ctx.embedded)
|
|
151
|
+
return dlqOps.purgeDlqEmbedded(ctx.name);
|
|
152
|
+
if (!ctx.tcp)
|
|
153
|
+
return 0;
|
|
154
|
+
const response = await ctx.tcp.send({ cmd: 'PurgeDlq', queue: ctx.name });
|
|
155
|
+
if (!response.ok)
|
|
156
|
+
return 0;
|
|
157
|
+
return (response.count ?? 0);
|
|
158
|
+
}
|
|
84
159
|
/** Retry completed job */
|
|
85
160
|
export function retryCompleted(ctx, id) {
|
|
86
161
|
if (ctx.embedded) {
|
|
@@ -19,6 +19,8 @@ export function getDlqContext(manager) {
|
|
|
19
19
|
return {
|
|
20
20
|
shards: getShards(manager),
|
|
21
21
|
jobIndex: manager.getJobIndex(),
|
|
22
|
+
jobResults: manager.jobResults,
|
|
23
|
+
jobLogs: manager.jobLogs,
|
|
22
24
|
// #110-class: without storage, retryDlqByFilter's deleteDlqEntry/insertJob
|
|
23
25
|
// silently no-op — filtered retries were never persisted in embedded mode
|
|
24
26
|
// (dlq rows resurrected the jobs into the DLQ on restart).
|
|
@@ -29,7 +29,7 @@ export interface JobReflectionMeta {
|
|
|
29
29
|
}
|
|
30
30
|
/** Create a full Job proxy with TCP methods */
|
|
31
31
|
export declare function createJobProxy<T>(id: string, name: string, data: T, ctx: JobProxyContext, meta?: JobReflectionMeta): Job<T>;
|
|
32
|
-
interface SimpleJobContext {
|
|
32
|
+
export interface SimpleJobContext {
|
|
33
33
|
queueName: string;
|
|
34
34
|
/** Execution mode — determines whether to use embedded manager or TCP */
|
|
35
35
|
embedded?: boolean;
|
|
@@ -10,12 +10,29 @@ interface ControlContext {
|
|
|
10
10
|
}
|
|
11
11
|
/** Pause the queue */
|
|
12
12
|
export declare function pause(ctx: ControlContext): void;
|
|
13
|
+
/** Pause the queue and resolve once the server has processed it. */
|
|
14
|
+
export declare function pauseAsync(ctx: ControlContext): Promise<void>;
|
|
13
15
|
/** Resume the queue */
|
|
14
16
|
export declare function resume(ctx: ControlContext): void;
|
|
17
|
+
/** Resume the queue and resolve once the server has processed it. */
|
|
18
|
+
export declare function resumeAsync(ctx: ControlContext): Promise<void>;
|
|
15
19
|
/** Drain the queue (remove all waiting jobs) */
|
|
16
20
|
export declare function drain(ctx: ControlContext): void;
|
|
21
|
+
/**
|
|
22
|
+
* Drain the queue and resolve with the number of removed jobs once the
|
|
23
|
+
* server has processed it. Same ordering guarantee as obliterateAsync():
|
|
24
|
+
* jobs added after resolution cannot be caught by a late-arriving drain.
|
|
25
|
+
*/
|
|
26
|
+
export declare function drainAsync(ctx: ControlContext): Promise<number>;
|
|
17
27
|
/** Obliterate the queue (remove all jobs and data) */
|
|
18
28
|
export declare function obliterate(ctx: ControlContext): void;
|
|
29
|
+
/**
|
|
30
|
+
* Obliterate the queue and resolve once the server has processed it.
|
|
31
|
+
* The fire-and-forget obliterate() gives no ordering guarantee over a
|
|
32
|
+
* multi-connection pool: a PUSH sent right after it can be processed first
|
|
33
|
+
* and then wiped. Await this variant before enqueuing follow-up jobs.
|
|
34
|
+
*/
|
|
35
|
+
export declare function obliterateAsync(ctx: ControlContext): Promise<void>;
|
|
19
36
|
/** Check if queue is paused (sync, embedded only) */
|
|
20
37
|
export declare function isPaused(ctx: ControlContext): boolean;
|
|
21
38
|
/** Check if queue is paused (async, works with TCP) */
|
|
@@ -10,6 +10,13 @@ export function pause(ctx) {
|
|
|
10
10
|
else if (ctx.tcp)
|
|
11
11
|
void ctx.tcp.send({ cmd: 'Pause', queue: ctx.name });
|
|
12
12
|
}
|
|
13
|
+
/** Pause the queue and resolve once the server has processed it. */
|
|
14
|
+
export async function pauseAsync(ctx) {
|
|
15
|
+
if (ctx.embedded)
|
|
16
|
+
getSharedManager().pause(ctx.name);
|
|
17
|
+
else if (ctx.tcp)
|
|
18
|
+
await ctx.tcp.send({ cmd: 'Pause', queue: ctx.name });
|
|
19
|
+
}
|
|
13
20
|
/** Resume the queue */
|
|
14
21
|
export function resume(ctx) {
|
|
15
22
|
if (ctx.embedded)
|
|
@@ -17,6 +24,13 @@ export function resume(ctx) {
|
|
|
17
24
|
else if (ctx.tcp)
|
|
18
25
|
void ctx.tcp.send({ cmd: 'Resume', queue: ctx.name });
|
|
19
26
|
}
|
|
27
|
+
/** Resume the queue and resolve once the server has processed it. */
|
|
28
|
+
export async function resumeAsync(ctx) {
|
|
29
|
+
if (ctx.embedded)
|
|
30
|
+
getSharedManager().resume(ctx.name);
|
|
31
|
+
else if (ctx.tcp)
|
|
32
|
+
await ctx.tcp.send({ cmd: 'Resume', queue: ctx.name });
|
|
33
|
+
}
|
|
20
34
|
/** Drain the queue (remove all waiting jobs) */
|
|
21
35
|
export function drain(ctx) {
|
|
22
36
|
if (ctx.embedded)
|
|
@@ -24,6 +38,21 @@ export function drain(ctx) {
|
|
|
24
38
|
else if (ctx.tcp)
|
|
25
39
|
void ctx.tcp.send({ cmd: 'Drain', queue: ctx.name });
|
|
26
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* Drain the queue and resolve with the number of removed jobs once the
|
|
43
|
+
* server has processed it. Same ordering guarantee as obliterateAsync():
|
|
44
|
+
* jobs added after resolution cannot be caught by a late-arriving drain.
|
|
45
|
+
*/
|
|
46
|
+
export async function drainAsync(ctx) {
|
|
47
|
+
if (ctx.embedded)
|
|
48
|
+
return getSharedManager().drain(ctx.name);
|
|
49
|
+
if (!ctx.tcp)
|
|
50
|
+
return 0;
|
|
51
|
+
const response = await ctx.tcp.send({ cmd: 'Drain', queue: ctx.name });
|
|
52
|
+
if (!response.ok)
|
|
53
|
+
return 0;
|
|
54
|
+
return (response.count ?? 0);
|
|
55
|
+
}
|
|
27
56
|
/** Obliterate the queue (remove all jobs and data) */
|
|
28
57
|
export function obliterate(ctx) {
|
|
29
58
|
if (ctx.embedded)
|
|
@@ -31,6 +60,18 @@ export function obliterate(ctx) {
|
|
|
31
60
|
else if (ctx.tcp)
|
|
32
61
|
void ctx.tcp.send({ cmd: 'Obliterate', queue: ctx.name });
|
|
33
62
|
}
|
|
63
|
+
/**
|
|
64
|
+
* Obliterate the queue and resolve once the server has processed it.
|
|
65
|
+
* The fire-and-forget obliterate() gives no ordering guarantee over a
|
|
66
|
+
* multi-connection pool: a PUSH sent right after it can be processed first
|
|
67
|
+
* and then wiped. Await this variant before enqueuing follow-up jobs.
|
|
68
|
+
*/
|
|
69
|
+
export async function obliterateAsync(ctx) {
|
|
70
|
+
if (ctx.embedded)
|
|
71
|
+
getSharedManager().obliterate(ctx.name);
|
|
72
|
+
else if (ctx.tcp)
|
|
73
|
+
await ctx.tcp.send({ cmd: 'Obliterate', queue: ctx.name });
|
|
74
|
+
}
|
|
34
75
|
/** Check if queue is paused (sync, embedded only) */
|
|
35
76
|
export function isPaused(ctx) {
|
|
36
77
|
if (!ctx.embedded)
|
|
@@ -30,6 +30,7 @@ export function getJobCounts(ctx) {
|
|
|
30
30
|
failed: counts.failed,
|
|
31
31
|
delayed: counts.delayed,
|
|
32
32
|
paused: pv.paused,
|
|
33
|
+
'waiting-children': counts['waiting-children'],
|
|
33
34
|
};
|
|
34
35
|
}
|
|
35
36
|
/** Get job counts (async, works with TCP) */
|
|
@@ -47,6 +48,7 @@ export async function getJobCountsAsync(ctx) {
|
|
|
47
48
|
failed: 0,
|
|
48
49
|
delayed: 0,
|
|
49
50
|
paused: 0,
|
|
51
|
+
'waiting-children': 0,
|
|
50
52
|
};
|
|
51
53
|
}
|
|
52
54
|
const counts = response.counts;
|
|
@@ -58,6 +60,7 @@ export async function getJobCountsAsync(ctx) {
|
|
|
58
60
|
failed: counts?.failed ?? 0,
|
|
59
61
|
delayed: counts?.delayed ?? 0,
|
|
60
62
|
paused: counts?.paused ?? 0,
|
|
63
|
+
'waiting-children': counts?.['waiting-children'] ?? 0,
|
|
61
64
|
};
|
|
62
65
|
}
|
|
63
66
|
/** Get waiting job count */
|
|
@@ -74,9 +74,13 @@ export declare class Queue<T = unknown> {
|
|
|
74
74
|
getCountsPerPriority(): Record<number, number>;
|
|
75
75
|
getCountsPerPriorityAsync(): Promise<Record<number, number>>;
|
|
76
76
|
pause(): void;
|
|
77
|
+
pauseAsync(): Promise<void>;
|
|
77
78
|
resume(): void;
|
|
79
|
+
resumeAsync(): Promise<void>;
|
|
78
80
|
drain(): void;
|
|
81
|
+
drainAsync(): Promise<number>;
|
|
79
82
|
obliterate(): void;
|
|
83
|
+
obliterateAsync(): Promise<void>;
|
|
80
84
|
isPaused(): boolean;
|
|
81
85
|
isPausedAsync(): Promise<boolean>;
|
|
82
86
|
waitUntilReady(): Promise<void>;
|
|
@@ -106,23 +110,32 @@ export declare class Queue<T = unknown> {
|
|
|
106
110
|
changeJobPriority(id: string, opts: ChangePriorityOpts): Promise<void>;
|
|
107
111
|
extendJobLock(id: string, token: string, duration: number): Promise<number>;
|
|
108
112
|
setStallConfig(config: Partial<StallConfig>): void;
|
|
113
|
+
setStallConfigAsync(config: Partial<StallConfig>): Promise<void>;
|
|
109
114
|
getStallConfig(): StallConfig;
|
|
110
115
|
getStallConfigAsync(): Promise<StallConfig>;
|
|
111
116
|
setDlqConfig(config: Partial<DlqConfig>): void;
|
|
117
|
+
setDlqConfigAsync(config: Partial<DlqConfig>): Promise<void>;
|
|
112
118
|
getDlqConfig(): DlqConfig;
|
|
113
119
|
getDlqConfigAsync(): Promise<DlqConfig>;
|
|
114
120
|
getDlq(filter?: DlqFilter): DlqEntry<T>[];
|
|
121
|
+
getDlqJobsAsync(count?: number): Promise<Job<T>[]>;
|
|
115
122
|
getDlqStats(): DlqStats;
|
|
116
123
|
retryDlq(id?: string): number;
|
|
124
|
+
retryDlqAsync(id?: string): Promise<number>;
|
|
117
125
|
retryDlqByFilter(filter: DlqFilter): number;
|
|
118
126
|
purgeDlq(): number;
|
|
127
|
+
purgeDlqAsync(): Promise<number>;
|
|
119
128
|
retryCompleted(id?: string): number;
|
|
120
129
|
retryCompletedAsync(id?: string): Promise<number>;
|
|
121
130
|
setGlobalConcurrency(concurrency: number): void;
|
|
131
|
+
setGlobalConcurrencyAsync(concurrency: number): Promise<void>;
|
|
122
132
|
removeGlobalConcurrency(): void;
|
|
133
|
+
removeGlobalConcurrencyAsync(): Promise<void>;
|
|
123
134
|
getGlobalConcurrency(): Promise<number | null>;
|
|
124
135
|
setGlobalRateLimit(max: number, duration?: number): void;
|
|
136
|
+
setGlobalRateLimitAsync(max: number, duration?: number): Promise<void>;
|
|
125
137
|
removeGlobalRateLimit(): void;
|
|
138
|
+
removeGlobalRateLimitAsync(): Promise<void>;
|
|
126
139
|
getGlobalRateLimit(): Promise<{
|
|
127
140
|
max: number;
|
|
128
141
|
duration: number;
|
|
@@ -262,15 +262,27 @@ export class Queue {
|
|
|
262
262
|
pause() {
|
|
263
263
|
controlOps.pause(this.ctx);
|
|
264
264
|
}
|
|
265
|
+
pauseAsync() {
|
|
266
|
+
return controlOps.pauseAsync(this.ctx);
|
|
267
|
+
}
|
|
265
268
|
resume() {
|
|
266
269
|
controlOps.resume(this.ctx);
|
|
267
270
|
}
|
|
271
|
+
resumeAsync() {
|
|
272
|
+
return controlOps.resumeAsync(this.ctx);
|
|
273
|
+
}
|
|
268
274
|
drain() {
|
|
269
275
|
controlOps.drain(this.ctx);
|
|
270
276
|
}
|
|
277
|
+
drainAsync() {
|
|
278
|
+
return controlOps.drainAsync(this.ctx);
|
|
279
|
+
}
|
|
271
280
|
obliterate() {
|
|
272
281
|
controlOps.obliterate(this.ctx);
|
|
273
282
|
}
|
|
283
|
+
obliterateAsync() {
|
|
284
|
+
return controlOps.obliterateAsync(this.ctx);
|
|
285
|
+
}
|
|
274
286
|
isPaused() {
|
|
275
287
|
return controlOps.isPaused(this.ctx);
|
|
276
288
|
}
|
|
@@ -333,6 +345,9 @@ export class Queue {
|
|
|
333
345
|
setStallConfig(config) {
|
|
334
346
|
stallOps.setStallConfig(this.ctx, config);
|
|
335
347
|
}
|
|
348
|
+
setStallConfigAsync(config) {
|
|
349
|
+
return stallOps.setStallConfigAsync(this.ctx, config);
|
|
350
|
+
}
|
|
336
351
|
getStallConfig() {
|
|
337
352
|
return stallOps.getStallConfig(this.ctx);
|
|
338
353
|
}
|
|
@@ -343,6 +358,9 @@ export class Queue {
|
|
|
343
358
|
setDlqConfig(config) {
|
|
344
359
|
dlqOps.setDlqConfig(this.ctx, config);
|
|
345
360
|
}
|
|
361
|
+
setDlqConfigAsync(config) {
|
|
362
|
+
return dlqOps.setDlqConfigAsync(this.ctx, config);
|
|
363
|
+
}
|
|
346
364
|
getDlqConfig() {
|
|
347
365
|
return dlqOps.getDlqConfig(this.ctx);
|
|
348
366
|
}
|
|
@@ -352,18 +370,27 @@ export class Queue {
|
|
|
352
370
|
getDlq(filter) {
|
|
353
371
|
return dlqOps.getDlq(this.ctx, filter);
|
|
354
372
|
}
|
|
373
|
+
getDlqJobsAsync(count) {
|
|
374
|
+
return dlqOps.getDlqJobsAsync(this.queryCtx, count);
|
|
375
|
+
}
|
|
355
376
|
getDlqStats() {
|
|
356
377
|
return dlqOps.getDlqStats(this.ctx);
|
|
357
378
|
}
|
|
358
379
|
retryDlq(id) {
|
|
359
380
|
return dlqOps.retryDlq(this.ctx, id);
|
|
360
381
|
}
|
|
382
|
+
retryDlqAsync(id) {
|
|
383
|
+
return dlqOps.retryDlqAsync(this.ctx, id);
|
|
384
|
+
}
|
|
361
385
|
retryDlqByFilter(filter) {
|
|
362
386
|
return dlqOps.retryDlqByFilter(this.ctx, filter);
|
|
363
387
|
}
|
|
364
388
|
purgeDlq() {
|
|
365
389
|
return dlqOps.purgeDlq(this.ctx);
|
|
366
390
|
}
|
|
391
|
+
purgeDlqAsync() {
|
|
392
|
+
return dlqOps.purgeDlqAsync(this.ctx);
|
|
393
|
+
}
|
|
367
394
|
retryCompleted(id) {
|
|
368
395
|
return dlqOps.retryCompleted(this.ctx, id);
|
|
369
396
|
}
|
|
@@ -374,18 +401,30 @@ export class Queue {
|
|
|
374
401
|
setGlobalConcurrency(concurrency) {
|
|
375
402
|
rateLimitOps.setGlobalConcurrency(this.ctx, concurrency);
|
|
376
403
|
}
|
|
404
|
+
setGlobalConcurrencyAsync(concurrency) {
|
|
405
|
+
return rateLimitOps.setGlobalConcurrencyAsync(this.ctx, concurrency);
|
|
406
|
+
}
|
|
377
407
|
removeGlobalConcurrency() {
|
|
378
408
|
rateLimitOps.removeGlobalConcurrency(this.ctx);
|
|
379
409
|
}
|
|
410
|
+
removeGlobalConcurrencyAsync() {
|
|
411
|
+
return rateLimitOps.removeGlobalConcurrencyAsync(this.ctx);
|
|
412
|
+
}
|
|
380
413
|
getGlobalConcurrency() {
|
|
381
414
|
return rateLimitOps.getGlobalConcurrency(this.ctx);
|
|
382
415
|
}
|
|
383
416
|
setGlobalRateLimit(max, duration) {
|
|
384
417
|
rateLimitOps.setGlobalRateLimit(this.ctx, max, duration);
|
|
385
418
|
}
|
|
419
|
+
setGlobalRateLimitAsync(max, duration) {
|
|
420
|
+
return rateLimitOps.setGlobalRateLimitAsync(this.ctx, max, duration);
|
|
421
|
+
}
|
|
386
422
|
removeGlobalRateLimit() {
|
|
387
423
|
rateLimitOps.removeGlobalRateLimit(this.ctx);
|
|
388
424
|
}
|
|
425
|
+
removeGlobalRateLimitAsync() {
|
|
426
|
+
return rateLimitOps.removeGlobalRateLimitAsync(this.ctx);
|
|
427
|
+
}
|
|
389
428
|
getGlobalRateLimit() {
|
|
390
429
|
return rateLimitOps.getGlobalRateLimit(this.ctx);
|
|
391
430
|
}
|
|
@@ -9,20 +9,35 @@ interface RateLimitContext {
|
|
|
9
9
|
}
|
|
10
10
|
/** Set global concurrency limit */
|
|
11
11
|
export declare function setGlobalConcurrency(ctx: RateLimitContext, concurrency: number): void;
|
|
12
|
+
/** Set global concurrency limit and resolve once the server has applied it. */
|
|
13
|
+
export declare function setGlobalConcurrencyAsync(ctx: RateLimitContext, concurrency: number): Promise<void>;
|
|
12
14
|
/** Remove global concurrency limit */
|
|
13
15
|
export declare function removeGlobalConcurrency(ctx: RateLimitContext): void;
|
|
16
|
+
/** Remove global concurrency limit and resolve once the server has applied it. */
|
|
17
|
+
export declare function removeGlobalConcurrencyAsync(ctx: RateLimitContext): Promise<void>;
|
|
14
18
|
/** Get global concurrency limit */
|
|
15
19
|
export declare function getGlobalConcurrency(_ctx: RateLimitContext): Promise<number | null>;
|
|
16
|
-
/**
|
|
17
|
-
|
|
20
|
+
/**
|
|
21
|
+
* Set global rate limit: `max` jobs per `duration` ms (default 1000ms).
|
|
22
|
+
* The window is honored in both embedded and TCP modes.
|
|
23
|
+
*/
|
|
24
|
+
export declare function setGlobalRateLimit(ctx: RateLimitContext, max: number, duration?: number): void;
|
|
25
|
+
/** Set global rate limit and resolve once the server has applied it. */
|
|
26
|
+
export declare function setGlobalRateLimitAsync(ctx: RateLimitContext, max: number, duration?: number): Promise<void>;
|
|
18
27
|
/** Remove global rate limit */
|
|
19
28
|
export declare function removeGlobalRateLimit(ctx: RateLimitContext): void;
|
|
29
|
+
/** Remove global rate limit and resolve once the server has applied it. */
|
|
30
|
+
export declare function removeGlobalRateLimitAsync(ctx: RateLimitContext): Promise<void>;
|
|
20
31
|
/** Get global rate limit */
|
|
21
32
|
export declare function getGlobalRateLimit(_ctx: RateLimitContext): Promise<{
|
|
22
33
|
max: number;
|
|
23
34
|
duration: number;
|
|
24
35
|
} | null>;
|
|
25
|
-
/**
|
|
36
|
+
/**
|
|
37
|
+
* Set temporary rate limit with expiration. The expiry lives broker-side
|
|
38
|
+
* (RateLimit `ttl`), so it survives client exit and works identically in
|
|
39
|
+
* embedded and TCP modes — no client timer involved.
|
|
40
|
+
*/
|
|
26
41
|
export declare function rateLimit(ctx: RateLimitContext, expireTimeMs: number): Promise<void>;
|
|
27
42
|
/** Get rate limit TTL */
|
|
28
43
|
export declare function getRateLimitTtl(_ctx: RateLimitContext, _maxJobs?: number): Promise<number>;
|
|
@@ -11,6 +11,13 @@ export function setGlobalConcurrency(ctx, concurrency) {
|
|
|
11
11
|
void ctx.tcp.send({ cmd: 'SetConcurrency', queue: ctx.name, limit: concurrency });
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
|
+
/** Set global concurrency limit and resolve once the server has applied it. */
|
|
15
|
+
export async function setGlobalConcurrencyAsync(ctx, concurrency) {
|
|
16
|
+
if (ctx.embedded)
|
|
17
|
+
getSharedManager().setConcurrency(ctx.name, concurrency);
|
|
18
|
+
else if (ctx.tcp)
|
|
19
|
+
await ctx.tcp.send({ cmd: 'SetConcurrency', queue: ctx.name, limit: concurrency });
|
|
20
|
+
}
|
|
14
21
|
/** Remove global concurrency limit */
|
|
15
22
|
export function removeGlobalConcurrency(ctx) {
|
|
16
23
|
if (ctx.embedded) {
|
|
@@ -20,19 +27,36 @@ export function removeGlobalConcurrency(ctx) {
|
|
|
20
27
|
void ctx.tcp.send({ cmd: 'ClearConcurrency', queue: ctx.name });
|
|
21
28
|
}
|
|
22
29
|
}
|
|
30
|
+
/** Remove global concurrency limit and resolve once the server has applied it. */
|
|
31
|
+
export async function removeGlobalConcurrencyAsync(ctx) {
|
|
32
|
+
if (ctx.embedded)
|
|
33
|
+
getSharedManager().clearConcurrency(ctx.name);
|
|
34
|
+
else if (ctx.tcp)
|
|
35
|
+
await ctx.tcp.send({ cmd: 'ClearConcurrency', queue: ctx.name });
|
|
36
|
+
}
|
|
23
37
|
/** Get global concurrency limit */
|
|
24
38
|
export function getGlobalConcurrency(_ctx) {
|
|
25
39
|
return Promise.resolve(null);
|
|
26
40
|
}
|
|
27
|
-
/**
|
|
28
|
-
|
|
41
|
+
/**
|
|
42
|
+
* Set global rate limit: `max` jobs per `duration` ms (default 1000ms).
|
|
43
|
+
* The window is honored in both embedded and TCP modes.
|
|
44
|
+
*/
|
|
45
|
+
export function setGlobalRateLimit(ctx, max, duration) {
|
|
29
46
|
if (ctx.embedded) {
|
|
30
|
-
getSharedManager().setRateLimit(ctx.name, max);
|
|
47
|
+
getSharedManager().setRateLimit(ctx.name, max, duration);
|
|
31
48
|
}
|
|
32
49
|
else if (ctx.tcp) {
|
|
33
|
-
void ctx.tcp.send({ cmd: 'RateLimit', queue: ctx.name, limit: max });
|
|
50
|
+
void ctx.tcp.send({ cmd: 'RateLimit', queue: ctx.name, limit: max, duration });
|
|
34
51
|
}
|
|
35
52
|
}
|
|
53
|
+
/** Set global rate limit and resolve once the server has applied it. */
|
|
54
|
+
export async function setGlobalRateLimitAsync(ctx, max, duration) {
|
|
55
|
+
if (ctx.embedded)
|
|
56
|
+
getSharedManager().setRateLimit(ctx.name, max, duration);
|
|
57
|
+
else if (ctx.tcp)
|
|
58
|
+
await ctx.tcp.send({ cmd: 'RateLimit', queue: ctx.name, limit: max, duration });
|
|
59
|
+
}
|
|
36
60
|
/** Remove global rate limit */
|
|
37
61
|
export function removeGlobalRateLimit(ctx) {
|
|
38
62
|
if (ctx.embedded) {
|
|
@@ -42,20 +66,31 @@ export function removeGlobalRateLimit(ctx) {
|
|
|
42
66
|
void ctx.tcp.send({ cmd: 'RateLimitClear', queue: ctx.name });
|
|
43
67
|
}
|
|
44
68
|
}
|
|
69
|
+
/** Remove global rate limit and resolve once the server has applied it. */
|
|
70
|
+
export async function removeGlobalRateLimitAsync(ctx) {
|
|
71
|
+
if (ctx.embedded)
|
|
72
|
+
getSharedManager().clearRateLimit(ctx.name);
|
|
73
|
+
else if (ctx.tcp)
|
|
74
|
+
await ctx.tcp.send({ cmd: 'RateLimitClear', queue: ctx.name });
|
|
75
|
+
}
|
|
45
76
|
/** Get global rate limit */
|
|
46
77
|
export function getGlobalRateLimit(_ctx) {
|
|
47
78
|
return Promise.resolve(null);
|
|
48
79
|
}
|
|
49
|
-
/**
|
|
80
|
+
/**
|
|
81
|
+
* Set temporary rate limit with expiration. The expiry lives broker-side
|
|
82
|
+
* (RateLimit `ttl`), so it survives client exit and works identically in
|
|
83
|
+
* embedded and TCP modes — no client timer involved.
|
|
84
|
+
*/
|
|
50
85
|
export async function rateLimit(ctx, expireTimeMs) {
|
|
86
|
+
if (!Number.isFinite(expireTimeMs) || expireTimeMs <= 0) {
|
|
87
|
+
throw new Error(`rateLimit: expireTimeMs must be a positive finite number, got ${expireTimeMs}`);
|
|
88
|
+
}
|
|
51
89
|
if (ctx.embedded) {
|
|
52
|
-
getSharedManager().setRateLimit(ctx.name, 1);
|
|
53
|
-
setTimeout(() => {
|
|
54
|
-
getSharedManager().clearRateLimit(ctx.name);
|
|
55
|
-
}, expireTimeMs);
|
|
90
|
+
getSharedManager().setRateLimit(ctx.name, 1, undefined, expireTimeMs);
|
|
56
91
|
}
|
|
57
92
|
else if (ctx.tcp) {
|
|
58
|
-
await ctx.tcp.send({ cmd: 'RateLimit', queue: ctx.name, limit: 1 });
|
|
93
|
+
await ctx.tcp.send({ cmd: 'RateLimit', queue: ctx.name, limit: 1, ttl: expireTimeMs });
|
|
59
94
|
}
|
|
60
95
|
}
|
|
61
96
|
/** Get rate limit TTL */
|
|
@@ -11,6 +11,8 @@ interface StallContext {
|
|
|
11
11
|
}
|
|
12
12
|
/** Set stall detection configuration */
|
|
13
13
|
export declare function setStallConfig(ctx: StallContext, config: Partial<StallConfig>): void;
|
|
14
|
+
/** Set stall detection configuration and resolve once the server has applied it. */
|
|
15
|
+
export declare function setStallConfigAsync(ctx: StallContext, config: Partial<StallConfig>): Promise<void>;
|
|
14
16
|
/** Get stall detection configuration */
|
|
15
17
|
export declare function getStallConfig(ctx: StallContext): StallConfig;
|
|
16
18
|
/** Get stall detection configuration (async, works in TCP mode) */
|
|
@@ -23,6 +23,18 @@ export function setStallConfig(ctx, config) {
|
|
|
23
23
|
void ctx.tcp.send({ cmd: 'SetStallConfig', queue: ctx.name, config });
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
|
+
/** Set stall detection configuration and resolve once the server has applied it. */
|
|
27
|
+
export async function setStallConfigAsync(ctx, config) {
|
|
28
|
+
if (ctx.embedded) {
|
|
29
|
+
dlqOps.setStallConfigEmbedded(ctx.name, config);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
if (!ctx.tcp)
|
|
33
|
+
return;
|
|
34
|
+
const current = tcpConfigCache.get(ctx.name) ?? { ...DEFAULT_STALL_CONFIG };
|
|
35
|
+
tcpConfigCache.set(ctx.name, { ...current, ...config });
|
|
36
|
+
await ctx.tcp.send({ cmd: 'SetStallConfig', queue: ctx.name, config });
|
|
37
|
+
}
|
|
26
38
|
/** Get stall detection configuration */
|
|
27
39
|
export function getStallConfig(ctx) {
|
|
28
40
|
if (ctx.embedded) {
|
|
@@ -54,6 +54,11 @@ export declare class DependencyTracker {
|
|
|
54
54
|
* Remove a parent job from waiting
|
|
55
55
|
*/
|
|
56
56
|
removeWaitingParent(jobId: JobId): Job | undefined;
|
|
57
|
+
/**
|
|
58
|
+
* Remove every dependency-gated job owned by a queue.
|
|
59
|
+
* Returns the removed ids so the caller can purge global indexes and storage.
|
|
60
|
+
*/
|
|
61
|
+
removeQueue(queue: string): JobId[];
|
|
57
62
|
/**
|
|
58
63
|
* Get a parent job waiting for children
|
|
59
64
|
*/
|
|
@@ -100,6 +100,26 @@ export class DependencyTracker {
|
|
|
100
100
|
}
|
|
101
101
|
return job;
|
|
102
102
|
}
|
|
103
|
+
/**
|
|
104
|
+
* Remove every dependency-gated job owned by a queue.
|
|
105
|
+
* Returns the removed ids so the caller can purge global indexes and storage.
|
|
106
|
+
*/
|
|
107
|
+
removeQueue(queue) {
|
|
108
|
+
const removed = [];
|
|
109
|
+
for (const [jobId, job] of this.waitingDeps) {
|
|
110
|
+
if (job.queue !== queue)
|
|
111
|
+
continue;
|
|
112
|
+
this.removeWaitingJob(jobId);
|
|
113
|
+
removed.push(jobId);
|
|
114
|
+
}
|
|
115
|
+
for (const [jobId, job] of this.waitingChildren) {
|
|
116
|
+
if (job.queue !== queue)
|
|
117
|
+
continue;
|
|
118
|
+
this.waitingChildren.delete(jobId);
|
|
119
|
+
removed.push(jobId);
|
|
120
|
+
}
|
|
121
|
+
return removed;
|
|
122
|
+
}
|
|
103
123
|
/**
|
|
104
124
|
* Get a parent job waiting for children
|
|
105
125
|
*/
|
|
@@ -20,10 +20,22 @@ export declare class LimiterManager {
|
|
|
20
20
|
pause(name: string): void;
|
|
21
21
|
/** Resume queue */
|
|
22
22
|
resume(name: string): void;
|
|
23
|
-
/**
|
|
24
|
-
|
|
23
|
+
/**
|
|
24
|
+
* Set rate limit for queue.
|
|
25
|
+
* @param durationMs window the limit applies to (default 1000ms): `limit`
|
|
26
|
+
* tokens refill over `durationMs`. Non-finite or non-positive → default.
|
|
27
|
+
* @param ttlMs auto-expiry: the limit clears itself after this many ms
|
|
28
|
+
* (lazy, checked on acquire/read). Non-finite or non-positive → permanent.
|
|
29
|
+
*/
|
|
30
|
+
setRateLimit(queue: string, limit: number, durationMs?: number, ttlMs?: number): void;
|
|
25
31
|
/** Clear rate limit */
|
|
26
32
|
clearRateLimit(queue: string): void;
|
|
33
|
+
/**
|
|
34
|
+
* Drop the rate limit if its TTL has elapsed. Lazy expiry: called from the
|
|
35
|
+
* acquire path and from limit reads, so no timer is needed and an expired
|
|
36
|
+
* limit can never throttle a pull.
|
|
37
|
+
*/
|
|
38
|
+
expireRateLimitIfNeeded(queue: string): void;
|
|
27
39
|
/** Try to acquire rate limit token */
|
|
28
40
|
tryAcquireRateLimit(queue: string): boolean;
|
|
29
41
|
/** Set concurrency limit for queue */
|