bunqueue 2.9.0 → 2.9.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/README.md +7 -3
- package/dist/application/background/recovery/active.d.ts +1 -0
- package/dist/application/background/recovery/active.js +12 -0
- package/dist/application/background/recovery/index.js +3 -1
- package/dist/application/background/recovery/pending.js +1 -0
- package/dist/application/cleanupTasks.js +4 -16
- package/dist/application/contextFactory.js +3 -0
- package/dist/application/dlqManager.js +1 -0
- package/dist/application/dlqRetry.js +1 -0
- package/dist/application/eventsManager.d.ts +8 -1
- package/dist/application/eventsManager.js +76 -29
- package/dist/application/operations/ackHelpers.d.ts +1 -4
- package/dist/application/operations/ackHelpers.js +39 -14
- package/dist/application/operations/flowPush.js +1 -0
- package/dist/application/operations/flowValidation.js +4 -4
- package/dist/application/operations/pull.d.ts +7 -2
- package/dist/application/operations/pull.js +15 -57
- package/dist/application/operations/pullFinalization.d.ts +6 -0
- package/dist/application/operations/pullFinalization.js +69 -0
- package/dist/application/operations/pullStateTransition.d.ts +8 -7
- package/dist/application/operations/pullStateTransition.js +25 -18
- package/dist/application/operations/push.js +3 -0
- package/dist/application/operations/pushBatch.js +14 -7
- package/dist/application/operations/pushContext.d.ts +2 -1
- package/dist/application/postgres-queue-manager/control.d.ts +4 -0
- package/dist/application/postgres-queue-manager/control.js +24 -0
- package/dist/application/postgres-queue-manager/delivery.d.ts +5 -4
- package/dist/application/postgres-queue-manager/delivery.js +13 -10
- package/dist/application/postgres-queue-manager/groupQueries.d.ts +10 -0
- package/dist/application/postgres-queue-manager/groupQueries.js +40 -0
- package/dist/application/postgres-queue-manager/queries.d.ts +2 -2
- package/dist/application/postgres-queue-manager/queries.js +2 -2
- package/dist/application/queue-manager/control.js +1 -0
- package/dist/application/queue-manager/delivery.d.ts +5 -4
- package/dist/application/queue-manager/delivery.js +15 -8
- package/dist/application/queue-manager/limits.d.ts +11 -0
- package/dist/application/queue-manager/limits.js +61 -0
- package/dist/application/queue-manager/state.js +1 -1
- package/dist/application/queueTelemetryJournal.d.ts +2 -0
- package/dist/application/queueTelemetryJournal.js +23 -0
- package/dist/application/types/ack.d.ts +3 -1
- package/dist/cli/commandRouter.d.ts +1 -1
- package/dist/client/flowPush.js +6 -0
- package/dist/client/groupId.d.ts +1 -0
- package/dist/client/groupId.js +1 -0
- package/dist/client/index.d.ts +1 -1
- package/dist/client/jobHelpers.js +1 -0
- package/dist/client/queue/operations/add/bulk.js +4 -4
- package/dist/client/queue/operations/add/payload.d.ts +1 -0
- package/dist/client/queue/operations/add/payload.js +7 -1
- package/dist/client/queue/operations/add/single.js +3 -3
- package/dist/client/queue/operations/groups.d.ts +21 -0
- package/dist/client/queue/operations/groups.js +88 -0
- package/dist/client/queue/runtime/queries.d.ts +13 -0
- package/dist/client/queue/runtime/queries.js +31 -0
- package/dist/client/queue/runtime/state.d.ts +4 -0
- package/dist/client/queue/runtime/state.js +1 -0
- package/dist/client/types/index.d.ts +2 -2
- package/dist/client/types/options.d.ts +4 -0
- package/dist/client/types/worker.d.ts +8 -0
- package/dist/client/worker/runtime/execution.js +1 -0
- package/dist/client/worker/runtime/options.js +3 -0
- package/dist/client/worker/types/options.d.ts +2 -1
- package/dist/client/worker/workerPull.d.ts +2 -0
- package/dist/client/worker/workerPull.js +6 -4
- package/dist/domain/job/groupFifoOrder.d.ts +9 -0
- package/dist/domain/job/groupFifoOrder.js +26 -0
- package/dist/domain/queue/groupLimiterManager.d.ts +23 -0
- package/dist/domain/queue/groupLimiterManager.js +107 -0
- package/dist/domain/queue/groupScheduler.d.ts +31 -0
- package/dist/domain/queue/groupScheduler.js +256 -0
- package/dist/domain/queue/groupSchedulerOrder.d.ts +6 -0
- package/dist/domain/queue/groupSchedulerOrder.js +30 -0
- package/dist/domain/queue/priorityQueue.d.ts +13 -23
- package/dist/domain/queue/priorityQueue.js +53 -42
- package/dist/domain/queue/shard/keys.d.ts +1 -0
- package/dist/domain/queue/shard/keys.js +25 -2
- package/dist/domain/queue/shard/lifecycle.js +4 -0
- package/dist/domain/queue/shard/limits.d.ts +20 -1
- package/dist/domain/queue/shard/limits.js +56 -0
- package/dist/domain/queue/shard/state.d.ts +5 -0
- package/dist/domain/queue/shard/state.js +9 -1
- package/dist/domain/types/commands/core.d.ts +3 -0
- package/dist/domain/types/commands/limits.d.ts +41 -0
- package/dist/domain/types/commands/union.d.ts +1 -1
- package/dist/domain/types/group.d.ts +21 -0
- package/dist/domain/types/group.js +78 -0
- package/dist/domain/types/priorityQueue.d.ts +1 -0
- package/dist/infrastructure/persistence/jobOptionsBlob.d.ts +1 -0
- package/dist/infrastructure/persistence/jobOptionsBlob.js +10 -2
- package/dist/infrastructure/persistence/migrations.js +11 -0
- package/dist/infrastructure/persistence/postgres/admission.js +5 -2
- package/dist/infrastructure/persistence/postgres/batchAdmission.js +22 -4
- package/dist/infrastructure/persistence/postgres/claimBatch.d.ts +3 -0
- package/dist/infrastructure/persistence/postgres/claimBatch.js +16 -3
- package/dist/infrastructure/persistence/postgres/claimSelection.d.ts +8 -1
- package/dist/infrastructure/persistence/postgres/claimSelection.js +73 -131
- package/dist/infrastructure/persistence/postgres/claims.d.ts +8 -1
- package/dist/infrastructure/persistence/postgres/claims.js +19 -3
- package/dist/infrastructure/persistence/postgres/eventCatchupCursors.d.ts +32 -0
- package/dist/infrastructure/persistence/postgres/eventCatchupCursors.js +66 -0
- package/dist/infrastructure/persistence/postgres/eventJournalSchema.d.ts +2 -2
- package/dist/infrastructure/persistence/postgres/eventJournalSchema.js +16 -2
- package/dist/infrastructure/persistence/postgres/eventPruneWatermarks.d.ts +2 -0
- package/dist/infrastructure/persistence/postgres/eventPruneWatermarks.js +21 -3
- package/dist/infrastructure/persistence/postgres/events.d.ts +3 -3
- package/dist/infrastructure/persistence/postgres/events.js +44 -17
- package/dist/infrastructure/persistence/postgres/groupClaims.d.ts +15 -0
- package/dist/infrastructure/persistence/postgres/groupClaims.js +95 -0
- package/dist/infrastructure/persistence/postgres/groupSchema.d.ts +2 -0
- package/dist/infrastructure/persistence/postgres/groupSchema.js +155 -0
- package/dist/infrastructure/persistence/postgres/groupSchemaFingerprint.d.ts +3 -0
- package/dist/infrastructure/persistence/postgres/groupSchemaFingerprint.js +127 -0
- package/dist/infrastructure/persistence/postgres/groupStateRetention.d.ts +3 -0
- package/dist/infrastructure/persistence/postgres/groupStateRetention.js +93 -0
- package/dist/infrastructure/persistence/postgres/groups.d.ts +11 -0
- package/dist/infrastructure/persistence/postgres/groups.js +117 -0
- package/dist/infrastructure/persistence/postgres/queueDestruction.js +4 -0
- package/dist/infrastructure/persistence/postgres/runtime.d.ts +0 -1
- package/dist/infrastructure/persistence/postgres/runtime.js +3 -1
- package/dist/infrastructure/persistence/postgres/schema.d.ts +2 -2
- package/dist/infrastructure/persistence/postgres/schema.js +8 -4
- package/dist/infrastructure/persistence/postgres/schemaInitialization.js +6 -1
- package/dist/infrastructure/persistence/postgres/store.d.ts +11 -1
- package/dist/infrastructure/persistence/postgres/store.js +47 -3
- package/dist/infrastructure/persistence/postgres/telemetry.d.ts +2 -0
- package/dist/infrastructure/persistence/postgres/telemetry.js +33 -21
- package/dist/infrastructure/persistence/postgres/types.d.ts +1 -0
- package/dist/infrastructure/persistence/schema.d.ts +2 -2
- package/dist/infrastructure/persistence/schema.js +12 -1
- package/dist/infrastructure/persistence/sqlite/control.d.ts +14 -0
- package/dist/infrastructure/persistence/sqlite/control.js +69 -0
- package/dist/infrastructure/persistence/sqlite/jobs.d.ts +12 -0
- package/dist/infrastructure/persistence/sqlite/jobs.js +36 -0
- package/dist/infrastructure/persistence/sqlite/telemetry.d.ts +2 -1
- package/dist/infrastructure/persistence/sqlite/telemetry.js +5 -64
- package/dist/infrastructure/persistence/sqlite/telemetryWrites.d.ts +4 -0
- package/dist/infrastructure/persistence/sqlite/telemetryWrites.js +123 -0
- package/dist/infrastructure/persistence/sqliteSerializer.js +2 -0
- package/dist/infrastructure/server/handler-routes/control.js +13 -0
- package/dist/infrastructure/server/handlers/core.d.ts +0 -5
- package/dist/infrastructure/server/handlers/core.js +15 -18
- package/dist/infrastructure/server/handlers/groups.d.ts +11 -0
- package/dist/infrastructure/server/handlers/groups.js +55 -0
- package/dist/infrastructure/server/handlers/pushBatchValidation.js +4 -1
- package/dist/infrastructure/server/protocol/validation.d.ts +1 -0
- package/dist/infrastructure/server/protocol/validation.js +1 -0
- package/dist/infrastructure/server/protocol.d.ts +1 -1
- package/dist/infrastructure/server/protocol.js +1 -1
- package/package.json +2 -1
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { processingShardIndex } from '../../shared/hash';
|
|
2
|
+
import { throughputTracker } from '../throughputTracker';
|
|
3
|
+
function createPulledEvent(job, queue, ctx) {
|
|
4
|
+
if (!ctx.processingShards[processingShardIndex(job.id)].has(job.id))
|
|
5
|
+
return null;
|
|
6
|
+
return {
|
|
7
|
+
eventType: 'pulled',
|
|
8
|
+
queue,
|
|
9
|
+
jobId: job.id,
|
|
10
|
+
timestamp: Date.now(),
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
function persistActive(job, fallbackStartedAt, ctx) {
|
|
14
|
+
try {
|
|
15
|
+
ctx.storage?.markActive(job.id, job.startedAt ?? fallbackStartedAt, job.timeline);
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
// Non-fatal: the in-memory processing map remains authoritative.
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function persistActiveBatch(jobs, events, ctx) {
|
|
22
|
+
const storage = ctx.storage;
|
|
23
|
+
if (!storage || jobs.length === 0)
|
|
24
|
+
return;
|
|
25
|
+
try {
|
|
26
|
+
storage.markActiveBatch(jobs.map((job, index) => ({
|
|
27
|
+
jobId: job.id,
|
|
28
|
+
startedAt: job.startedAt ?? events[index].timestamp,
|
|
29
|
+
timeline: job.timeline,
|
|
30
|
+
})));
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
for (let index = 0; index < jobs.length; index++) {
|
|
34
|
+
persistActive(jobs[index], events[index].timestamp, ctx);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/** Persist and publish a single processing handoff. */
|
|
39
|
+
export function finalizeProcessing(job, queue, ctx) {
|
|
40
|
+
const event = createPulledEvent(job, queue, ctx);
|
|
41
|
+
if (!event)
|
|
42
|
+
return false;
|
|
43
|
+
persistActive(job, event.timestamp, ctx);
|
|
44
|
+
ctx.totalPulled.value++;
|
|
45
|
+
throughputTracker.pullRate.increment();
|
|
46
|
+
ctx.broadcast(event);
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
/** Persist and publish all processing handoffs with one durable state transaction. */
|
|
50
|
+
export function finalizeProcessingBatch(jobs, queue, ctx) {
|
|
51
|
+
const delivered = [];
|
|
52
|
+
const events = [];
|
|
53
|
+
for (const job of jobs) {
|
|
54
|
+
const event = createPulledEvent(job, queue, ctx);
|
|
55
|
+
if (!event)
|
|
56
|
+
continue;
|
|
57
|
+
delivered.push(job);
|
|
58
|
+
events.push(event);
|
|
59
|
+
}
|
|
60
|
+
persistActiveBatch(delivered, events, ctx);
|
|
61
|
+
ctx.totalPulled.value += BigInt(delivered.length);
|
|
62
|
+
throughputTracker.pullRate.increment(delivered.length);
|
|
63
|
+
if (ctx.broadcastBatch)
|
|
64
|
+
ctx.broadcastBatch(events);
|
|
65
|
+
else
|
|
66
|
+
for (const event of events)
|
|
67
|
+
ctx.broadcast(event);
|
|
68
|
+
return delivered;
|
|
69
|
+
}
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import type { Shard } from '../../domain/queue/shard';
|
|
5
5
|
import { type Job, type JobId } from '../../domain/types/job';
|
|
6
|
-
import type {
|
|
6
|
+
import type { GroupPullOptions } from '../../domain/types/group';
|
|
7
|
+
import type { EventType, JobEvent, JobLocation } from '../../domain/types/queue';
|
|
7
8
|
import type { SqliteStorage } from '../../infrastructure/persistence/sqlite';
|
|
8
9
|
import type { RWLock } from '../../shared/lock';
|
|
9
10
|
/** Dependencies shared by the single and batch pull paths. */
|
|
@@ -23,11 +24,13 @@ export interface PullContext {
|
|
|
23
24
|
jobId: JobId;
|
|
24
25
|
timestamp: number;
|
|
25
26
|
}) => void;
|
|
27
|
+
broadcastBatch?: (events: readonly JobEvent[]) => void;
|
|
26
28
|
dashboardEmit?: (event: string, data: Record<string, unknown>) => void;
|
|
27
29
|
}
|
|
28
30
|
export interface DequeueScan {
|
|
29
31
|
parked: Job[];
|
|
30
32
|
nextRunAt: number | null;
|
|
33
|
+
groupOptions?: GroupPullOptions;
|
|
31
34
|
}
|
|
32
35
|
export type DequeueResult = {
|
|
33
36
|
status: 'job';
|
|
@@ -35,15 +38,13 @@ export type DequeueResult = {
|
|
|
35
38
|
} | {
|
|
36
39
|
status: 'stop';
|
|
37
40
|
};
|
|
38
|
-
export declare function createDequeueScan(): DequeueScan;
|
|
41
|
+
export declare function createDequeueScan(groupOptions?: GroupPullOptions): DequeueScan;
|
|
39
42
|
/** Restore physical heap membership without changing logical queue state. */
|
|
40
43
|
export declare function restoreParkedJobs(shard: Shard, queue: string, scan: DequeueScan): void;
|
|
41
44
|
/**
|
|
42
|
-
* Remove the best eligible job
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
* shard critical section is held: time is fixed and active FIFO groups only
|
|
46
|
-
* grow. Its parked jobs therefore need to be restored only once after the batch.
|
|
45
|
+
* Remove the best eligible job from the shard's secondary group indexes.
|
|
46
|
+
* A batch reuses the same fixed timestamp and group defaults while its
|
|
47
|
+
* synchronous shard critical section is held.
|
|
47
48
|
*/
|
|
48
49
|
export declare function tryDequeueNextJob(shard: Shard, queue: string, now: number, ctx: PullContext, scan: DequeueScan): DequeueResult;
|
|
49
50
|
/** Restore a dequeued job when its handoff to the worker cannot complete. */
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
import { isExpired, isReady, MAX_TIMELINE_ENTRIES, } from '../../domain/types/job';
|
|
5
5
|
import { processingShardIndex } from '../../shared/hash';
|
|
6
6
|
import { withWriteLock } from '../../shared/lock';
|
|
7
|
-
export function createDequeueScan() {
|
|
8
|
-
return { parked: [], nextRunAt: null };
|
|
7
|
+
export function createDequeueScan(groupOptions) {
|
|
8
|
+
return { parked: [], nextRunAt: null, groupOptions };
|
|
9
9
|
}
|
|
10
10
|
/** Restore physical heap membership without changing logical queue state. */
|
|
11
11
|
export function restoreParkedJobs(shard, queue, scan) {
|
|
@@ -15,23 +15,30 @@ export function restoreParkedJobs(shard, queue, scan) {
|
|
|
15
15
|
scan.parked.length = 0;
|
|
16
16
|
}
|
|
17
17
|
/**
|
|
18
|
-
* Remove the best eligible job
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* shard critical section is held: time is fixed and active FIFO groups only
|
|
22
|
-
* grow. Its parked jobs therefore need to be restored only once after the batch.
|
|
18
|
+
* Remove the best eligible job from the shard's secondary group indexes.
|
|
19
|
+
* A batch reuses the same fixed timestamp and group defaults while its
|
|
20
|
+
* synchronous shard critical section is held.
|
|
23
21
|
*/
|
|
24
22
|
export function tryDequeueNextJob(shard, queue, now, ctx, scan) {
|
|
25
23
|
const priorityQueue = shard.getQueue(queue);
|
|
26
24
|
while (true) {
|
|
27
|
-
const
|
|
25
|
+
const grouped = shard.hasGroupScheduler(queue);
|
|
26
|
+
const candidate = grouped
|
|
27
|
+
? shard.peekGroupCandidate(queue, now, scan.groupOptions)
|
|
28
|
+
: { job: priorityQueue.peek(), nextRunAt: null };
|
|
29
|
+
if (grouped)
|
|
30
|
+
scan.nextRunAt = candidate.nextRunAt;
|
|
31
|
+
const job = candidate.job;
|
|
28
32
|
if (!job)
|
|
29
33
|
return { status: 'stop' };
|
|
30
34
|
if (isExpired(job, now)) {
|
|
31
35
|
// Persistence is removed first so a failed durable delete leaves the
|
|
32
36
|
// in-memory job available for a later attempt.
|
|
33
37
|
ctx.storage?.deleteJob(job.id);
|
|
34
|
-
|
|
38
|
+
if (grouped)
|
|
39
|
+
priorityQueue.remove(job.id);
|
|
40
|
+
else
|
|
41
|
+
priorityQueue.pop();
|
|
35
42
|
shard.decrementQueued(job.id);
|
|
36
43
|
ctx.jobIndex.delete(job.id);
|
|
37
44
|
ctx.dashboardEmit?.('job:expired', {
|
|
@@ -42,19 +49,13 @@ export function tryDequeueNextJob(shard, queue, now, ctx, scan) {
|
|
|
42
49
|
});
|
|
43
50
|
continue;
|
|
44
51
|
}
|
|
45
|
-
if (!isReady(job, now)) {
|
|
52
|
+
if (!grouped && !isReady(job, now)) {
|
|
46
53
|
const delayed = priorityQueue.pop();
|
|
47
54
|
if (delayed)
|
|
48
55
|
scan.parked.push(delayed);
|
|
49
56
|
scan.nextRunAt = scan.nextRunAt === null ? job.runAt : Math.min(scan.nextRunAt, job.runAt);
|
|
50
57
|
continue;
|
|
51
58
|
}
|
|
52
|
-
if (job.groupId && shard.isGroupActive(queue, job.groupId)) {
|
|
53
|
-
const blocked = priorityQueue.pop();
|
|
54
|
-
if (blocked)
|
|
55
|
-
scan.parked.push(blocked);
|
|
56
|
-
continue;
|
|
57
|
-
}
|
|
58
59
|
// Capacity is consumed only after an eligible job has been found.
|
|
59
60
|
if (!shard.tryAcquireConcurrency(queue)) {
|
|
60
61
|
ctx.dashboardEmit?.('concurrency:rejected', { queue });
|
|
@@ -65,14 +66,20 @@ export function tryDequeueNextJob(shard, queue, now, ctx, scan) {
|
|
|
65
66
|
ctx.dashboardEmit?.('ratelimit:rejected', { queue });
|
|
66
67
|
return { status: 'stop' };
|
|
67
68
|
}
|
|
68
|
-
|
|
69
|
+
if (job.groupId && !shard.acquireGroup(queue, job.groupId, scan.groupOptions, now)) {
|
|
70
|
+
shard.releaseConcurrency(queue);
|
|
71
|
+
return { status: 'stop' };
|
|
72
|
+
}
|
|
73
|
+
const dequeued = grouped ? priorityQueue.remove(job.id) : priorityQueue.pop();
|
|
69
74
|
if (!dequeued) {
|
|
75
|
+
if (job.groupId)
|
|
76
|
+
shard.releaseGroup(queue, job.groupId);
|
|
70
77
|
shard.releaseConcurrency(queue);
|
|
71
78
|
return { status: 'stop' };
|
|
72
79
|
}
|
|
73
80
|
shard.decrementQueued(dequeued.id);
|
|
74
81
|
if (dequeued.groupId)
|
|
75
|
-
shard.
|
|
82
|
+
shard.advanceGroup(queue, dequeued.groupId);
|
|
76
83
|
dequeued.startedAt = now;
|
|
77
84
|
dequeued.lastHeartbeat = now;
|
|
78
85
|
if (dequeued.timeline.length < MAX_TIMELINE_ENTRIES) {
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* Single-job push logic and stable batch re-export
|
|
4
4
|
*/
|
|
5
5
|
import { createJob } from '../../domain/types/job';
|
|
6
|
+
import { assertOptionalGroupId } from '../../domain/types/group';
|
|
6
7
|
import { shardIndex } from '../../shared/hash';
|
|
7
8
|
import { latencyTracker } from '../latencyTracker';
|
|
8
9
|
import { throughputTracker } from '../throughputTracker';
|
|
@@ -20,6 +21,7 @@ export { pushJobBatch } from './pushBatch';
|
|
|
20
21
|
* NOTE: customId check happens INSIDE lock to prevent race conditions
|
|
21
22
|
*/
|
|
22
23
|
export async function pushJob(queue, input, ctx) {
|
|
24
|
+
assertOptionalGroupId(input.groupId);
|
|
23
25
|
validateRepeatJobInput(input);
|
|
24
26
|
const startNs = Bun.nanoseconds();
|
|
25
27
|
const idx = shardIndex(queue);
|
|
@@ -58,6 +60,7 @@ export async function pushJob(queue, input, ctx) {
|
|
|
58
60
|
};
|
|
59
61
|
return;
|
|
60
62
|
}
|
|
63
|
+
shard.assignGroupFifoOrder(job);
|
|
61
64
|
const target = { queue, shard, shardIdx: idx };
|
|
62
65
|
let storageHandled = false;
|
|
63
66
|
if (linkParent) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createJob, normalizeJobPayload, } from '../../domain/types/job';
|
|
2
|
+
import { assertOptionalGroupId } from '../../domain/types/group';
|
|
2
3
|
import { shardIndex } from '../../shared/hash';
|
|
3
4
|
import { releaseDependencyCompletionPins } from '../dependencyCompletions';
|
|
4
5
|
import { latencyTracker } from '../latencyTracker';
|
|
@@ -13,6 +14,7 @@ import { withPushWriteLocks } from './pushLocks';
|
|
|
13
14
|
/** Push an ordered batch while preserving its accepted-prefix contract. */
|
|
14
15
|
export async function pushJobBatch(queue, inputs, ctx) {
|
|
15
16
|
for (const input of inputs) {
|
|
17
|
+
assertOptionalGroupId(input.groupId);
|
|
16
18
|
validateRepeatJobInput(input);
|
|
17
19
|
normalizeJobPayload(input);
|
|
18
20
|
}
|
|
@@ -43,6 +45,7 @@ export async function pushJobBatch(queue, inputs, ctx) {
|
|
|
43
45
|
resultIds.push(dedupResult.existingId);
|
|
44
46
|
continue;
|
|
45
47
|
}
|
|
48
|
+
shard.assignGroupFifoOrder(job);
|
|
46
49
|
const target = { queue, shard, shardIdx: idx };
|
|
47
50
|
let storageHandled = false;
|
|
48
51
|
if (linkParent) {
|
|
@@ -111,13 +114,17 @@ export async function pushJobBatch(queue, inputs, ctx) {
|
|
|
111
114
|
}
|
|
112
115
|
ctx.totalPushed.value += BigInt(acceptedJobs.length);
|
|
113
116
|
throughputTracker.pushRate.increment(acceptedJobs.length);
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
117
|
+
const events = acceptedJobs.map((job) => ({
|
|
118
|
+
eventType: 'pushed',
|
|
119
|
+
queue: job.queue,
|
|
120
|
+
jobId: job.id,
|
|
121
|
+
timestamp: now,
|
|
122
|
+
}));
|
|
123
|
+
if (ctx.broadcastBatch)
|
|
124
|
+
ctx.broadcastBatch(events);
|
|
125
|
+
else {
|
|
126
|
+
for (const event of events)
|
|
127
|
+
ctx.broadcast(event);
|
|
121
128
|
}
|
|
122
129
|
}
|
|
123
130
|
if (jobsToInsert.length > 0)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Shard } from '../../domain/queue/shard';
|
|
2
2
|
import type { Job, JobId } from '../../domain/types/job';
|
|
3
3
|
import type { JobLocation } from '../../domain/types/queue';
|
|
4
|
-
import { type EventType } from '../../domain/types/queue';
|
|
4
|
+
import { type EventType, type JobEvent } from '../../domain/types/queue';
|
|
5
5
|
import type { SqliteStorage } from '../../infrastructure/persistence/sqlite';
|
|
6
6
|
import type { RWLock } from '../../shared/lock';
|
|
7
7
|
import type { MapLike, SetLike } from '../../shared/lru';
|
|
@@ -34,6 +34,7 @@ export interface PushContext {
|
|
|
34
34
|
jobId: JobId;
|
|
35
35
|
timestamp: number;
|
|
36
36
|
}) => void;
|
|
37
|
+
broadcastBatch?: (events: readonly JobEvent[]) => void;
|
|
37
38
|
dashboardEmit?: (event: string, data: Record<string, unknown>) => void;
|
|
38
39
|
registerQueueName?: (queue: string) => void;
|
|
39
40
|
}
|
|
@@ -3,6 +3,10 @@ import { type StallConfig } from '../../domain/types/stall';
|
|
|
3
3
|
import { PostgresQueueManagerMaintenance } from './maintenance';
|
|
4
4
|
/** Durable queue controls and policies shared by every PostgreSQL broker. */
|
|
5
5
|
export declare class PostgresQueueManagerControl extends PostgresQueueManagerMaintenance {
|
|
6
|
+
setGroupRateLimit(queue: string, groupId: string, max: number, duration: number): Promise<void>;
|
|
7
|
+
removeGroupRateLimit(queue: string, groupId: string): Promise<number>;
|
|
8
|
+
setGroupConcurrency(queue: string, groupId: string, concurrency: number): Promise<void>;
|
|
9
|
+
removeGroupConcurrency(queue: string, groupId: string): Promise<number>;
|
|
6
10
|
pause(queue: string): void;
|
|
7
11
|
resume(queue: string): void;
|
|
8
12
|
pauseDurable(queue: string, paused: boolean): Promise<void>;
|
|
@@ -25,6 +25,30 @@ function normalizeDlq(current, patch) {
|
|
|
25
25
|
}
|
|
26
26
|
/** Durable queue controls and policies shared by every PostgreSQL broker. */
|
|
27
27
|
export class PostgresQueueManagerControl extends PostgresQueueManagerMaintenance {
|
|
28
|
+
async setGroupRateLimit(queue, groupId, max, duration) {
|
|
29
|
+
return await this.runPostgresOperation(async () => {
|
|
30
|
+
await this.postgresReady;
|
|
31
|
+
await this.postgresStore.setGroupRateLimit(queue, groupId, max, duration);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
async removeGroupRateLimit(queue, groupId) {
|
|
35
|
+
return await this.runPostgresOperation(async () => {
|
|
36
|
+
await this.postgresReady;
|
|
37
|
+
return await this.postgresStore.removeGroupRateLimit(queue, groupId);
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
async setGroupConcurrency(queue, groupId, concurrency) {
|
|
41
|
+
return await this.runPostgresOperation(async () => {
|
|
42
|
+
await this.postgresReady;
|
|
43
|
+
await this.postgresStore.setGroupConcurrency(queue, groupId, concurrency);
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
async removeGroupConcurrency(queue, groupId) {
|
|
47
|
+
return await this.runPostgresOperation(async () => {
|
|
48
|
+
await this.postgresReady;
|
|
49
|
+
return await this.postgresStore.removeGroupConcurrency(queue, groupId);
|
|
50
|
+
});
|
|
51
|
+
}
|
|
28
52
|
pause(queue) {
|
|
29
53
|
this.operations.runSync(() => {
|
|
30
54
|
this.setLocalQueueState(queue, { paused: true });
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import type { AtomicFlowBatchInput, AtomicFlowBatchResult } from '../../domain/types/flow';
|
|
2
|
+
import { type GroupPullOptions } from '../../domain/types/group';
|
|
2
3
|
import { type Job, type JobId, type JobInput } from '../../domain/types/job';
|
|
3
4
|
import { PostgresQueueManagerTerminalDelivery } from './terminalDelivery';
|
|
4
5
|
export declare class PostgresQueueManagerDelivery extends PostgresQueueManagerTerminalDelivery {
|
|
5
6
|
push(queue: string, input: JobInput): Promise<Job>;
|
|
6
7
|
pushBatch(queue: string, inputs: JobInput[]): Promise<JobId[]>;
|
|
7
8
|
pushFlow(batch: AtomicFlowBatchInput): Promise<AtomicFlowBatchResult>;
|
|
8
|
-
pull(queue: string, timeoutMs?: number, signal?: AbortSignal): Promise<Job | null>;
|
|
9
|
-
pullWithLock(queue: string, owner: string, timeoutMs?: number, lockTtl?: number, signal?: AbortSignal): Promise<{
|
|
9
|
+
pull(queue: string, timeoutMs?: number, signal?: AbortSignal, groupOptions?: GroupPullOptions): Promise<Job | null>;
|
|
10
|
+
pullWithLock(queue: string, owner: string, timeoutMs?: number, lockTtl?: number, signal?: AbortSignal, groupOptions?: GroupPullOptions): Promise<{
|
|
10
11
|
job: Job | null;
|
|
11
12
|
token: string | null;
|
|
12
13
|
}>;
|
|
13
|
-
pullBatch(queue: string, count: number, timeoutMs?: number, signal?: AbortSignal): Promise<Job[]>;
|
|
14
|
-
pullBatchWithLock(queue: string, count: number, owner: string, timeoutMs?: number, lockTtl?: number, signal?: AbortSignal): Promise<{
|
|
14
|
+
pullBatch(queue: string, count: number, timeoutMs?: number, signal?: AbortSignal, groupOptions?: GroupPullOptions): Promise<Job[]>;
|
|
15
|
+
pullBatchWithLock(queue: string, count: number, owner: string, timeoutMs?: number, lockTtl?: number, signal?: AbortSignal, groupOptions?: GroupPullOptions): Promise<{
|
|
15
16
|
jobs: Job[];
|
|
16
17
|
tokens: string[];
|
|
17
18
|
}>;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { assertGroupPullOptions } from '../../domain/types/group';
|
|
1
2
|
import { createJob, DEFAULT_LOCK_TTL, generateJobId, jobId, } from '../../domain/types/job';
|
|
2
3
|
import { validateRepeatJobInput } from '../repeatJobs';
|
|
3
4
|
import { PostgresQueueManagerTerminalDelivery } from './terminalDelivery';
|
|
@@ -34,35 +35,37 @@ export class PostgresQueueManagerDelivery extends PostgresQueueManagerTerminalDe
|
|
|
34
35
|
return { jobs };
|
|
35
36
|
});
|
|
36
37
|
}
|
|
37
|
-
async pull(queue, timeoutMs = 0, signal) {
|
|
38
|
-
const claims = await this.claimUntil(queue, 1, this.postgresStore.config.brokerId, timeoutMs, undefined, signal);
|
|
38
|
+
async pull(queue, timeoutMs = 0, signal, groupOptions) {
|
|
39
|
+
const claims = await this.claimUntil(queue, 1, this.postgresStore.config.brokerId, timeoutMs, undefined, signal, groupOptions);
|
|
39
40
|
return claims[0]?.job ?? null;
|
|
40
41
|
}
|
|
41
|
-
|
|
42
|
-
|
|
42
|
+
// oxlint-disable-next-line max-params -- public API includes cancellation and lease policy
|
|
43
|
+
async pullWithLock(queue, owner, timeoutMs = 0, lockTtl = DEFAULT_LOCK_TTL, signal, groupOptions) {
|
|
44
|
+
const claims = await this.claimUntil(queue, 1, owner, timeoutMs, lockTtl, signal, groupOptions);
|
|
43
45
|
const claim = claims[0];
|
|
44
46
|
return claim ? { job: claim.job, token: claim.token } : { job: null, token: null };
|
|
45
47
|
}
|
|
46
|
-
async pullBatch(queue, count, timeoutMs = 0, signal) {
|
|
47
|
-
const claims = await this.claimUntil(queue, count, this.postgresStore.config.brokerId, timeoutMs, undefined, signal);
|
|
48
|
+
async pullBatch(queue, count, timeoutMs = 0, signal, groupOptions) {
|
|
49
|
+
const claims = await this.claimUntil(queue, count, this.postgresStore.config.brokerId, timeoutMs, undefined, signal, groupOptions);
|
|
48
50
|
return claims.map((claim) => claim.job);
|
|
49
51
|
}
|
|
50
52
|
// oxlint-disable-next-line max-params -- public API includes cancellation and lease policy
|
|
51
|
-
async pullBatchWithLock(queue, count, owner, timeoutMs = 0, lockTtl = DEFAULT_LOCK_TTL, signal) {
|
|
52
|
-
const claims = await this.claimUntil(queue, count, owner, timeoutMs, lockTtl, signal);
|
|
53
|
+
async pullBatchWithLock(queue, count, owner, timeoutMs = 0, lockTtl = DEFAULT_LOCK_TTL, signal, groupOptions) {
|
|
54
|
+
const claims = await this.claimUntil(queue, count, owner, timeoutMs, lockTtl, signal, groupOptions);
|
|
53
55
|
return {
|
|
54
56
|
jobs: claims.map((claim) => claim.job),
|
|
55
57
|
tokens: claims.map((claim) => claim.token),
|
|
56
58
|
};
|
|
57
59
|
}
|
|
58
60
|
// oxlint-disable-next-line max-params -- internal bridge mirrors the public pull contract
|
|
59
|
-
async claimUntil(queue, count, owner, timeoutMs, leaseDurationMs, signal) {
|
|
61
|
+
async claimUntil(queue, count, owner, timeoutMs, leaseDurationMs, signal, groupOptions) {
|
|
62
|
+
assertGroupPullOptions(groupOptions);
|
|
60
63
|
await this.postgresReady;
|
|
61
64
|
await this.flushPostgresWrites();
|
|
62
65
|
const deadline = Date.now() + Math.max(0, timeoutMs);
|
|
63
66
|
do {
|
|
64
67
|
const claims = await this.runPostgresOperation(async () => {
|
|
65
|
-
const admitted = await this.postgresStore.claim(queue, count, owner, leaseDurationMs);
|
|
68
|
+
const admitted = await this.postgresStore.claim(queue, count, owner, leaseDurationMs, groupOptions);
|
|
66
69
|
for (const claim of admitted) {
|
|
67
70
|
this.applyPostgresClaim(claim);
|
|
68
71
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { PostgresQueueManagerState } from './state';
|
|
2
|
+
/** Database-authoritative group getters shared by every PostgreSQL broker. */
|
|
3
|
+
export declare class PostgresQueueManagerGroupQueries extends PostgresQueueManagerState {
|
|
4
|
+
getGroupJobsCount(queue: string, groupId: string): Promise<number>;
|
|
5
|
+
getGroupsJobsCount(queue: string): Promise<number>;
|
|
6
|
+
getGroupActiveCount(queue: string, groupId: string): Promise<number>;
|
|
7
|
+
getGroupRateLimit(queue: string, groupId: string): Promise<import("../../domain/types/group").GroupRateLimitOverride | null>;
|
|
8
|
+
getGroupRateLimitTtl(queue: string, groupId: string, maxJobs?: number): Promise<number>;
|
|
9
|
+
getGroupConcurrency(queue: string, groupId: string): Promise<number | null>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { PostgresQueueManagerState } from './state';
|
|
2
|
+
/** Database-authoritative group getters shared by every PostgreSQL broker. */
|
|
3
|
+
export class PostgresQueueManagerGroupQueries extends PostgresQueueManagerState {
|
|
4
|
+
async getGroupJobsCount(queue, groupId) {
|
|
5
|
+
return await this.runPostgresOperation(async () => {
|
|
6
|
+
await this.postgresReady;
|
|
7
|
+
return await this.postgresStore.getGroupJobsCount(queue, groupId);
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
async getGroupsJobsCount(queue) {
|
|
11
|
+
return await this.runPostgresOperation(async () => {
|
|
12
|
+
await this.postgresReady;
|
|
13
|
+
return await this.postgresStore.getGroupJobsCount(queue);
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
async getGroupActiveCount(queue, groupId) {
|
|
17
|
+
return await this.runPostgresOperation(async () => {
|
|
18
|
+
await this.postgresReady;
|
|
19
|
+
return await this.postgresStore.getGroupActiveCount(queue, groupId);
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
async getGroupRateLimit(queue, groupId) {
|
|
23
|
+
return await this.runPostgresOperation(async () => {
|
|
24
|
+
await this.postgresReady;
|
|
25
|
+
return await this.postgresStore.getGroupRateLimit(queue, groupId);
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
async getGroupRateLimitTtl(queue, groupId, maxJobs) {
|
|
29
|
+
return await this.runPostgresOperation(async () => {
|
|
30
|
+
await this.postgresReady;
|
|
31
|
+
return await this.postgresStore.getGroupRateLimitTtl(queue, groupId, maxJobs);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
async getGroupConcurrency(queue, groupId) {
|
|
35
|
+
return await this.runPostgresOperation(async () => {
|
|
36
|
+
await this.postgresReady;
|
|
37
|
+
return await this.postgresStore.getGroupConcurrency(queue, groupId);
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type DlqEntry, type DlqFilter, type DlqStats } from '../../domain/types/dlq';
|
|
2
2
|
import type { Job, JobId } from '../../domain/types/job';
|
|
3
|
-
import {
|
|
4
|
-
export declare class PostgresQueueManagerQueries extends
|
|
3
|
+
import { PostgresQueueManagerGroupQueries } from './groupQueries';
|
|
4
|
+
export declare class PostgresQueueManagerQueries extends PostgresQueueManagerGroupQueries {
|
|
5
5
|
getJobIndex(): Map<JobId, import("../../domain/types").JobLocation>;
|
|
6
6
|
getCompletedJobs(): Set<JobId>;
|
|
7
7
|
getDepCompletions(): Set<JobId>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { PostgresQueueManagerGroupQueries } from './groupQueries';
|
|
2
2
|
function jobCounts(counts, totals) {
|
|
3
3
|
return {
|
|
4
4
|
waiting: counts.waiting,
|
|
@@ -12,7 +12,7 @@ function jobCounts(counts, totals) {
|
|
|
12
12
|
totalFailed: Number(totals?.totalFailed ?? 0n),
|
|
13
13
|
};
|
|
14
14
|
}
|
|
15
|
-
export class PostgresQueueManagerQueries extends
|
|
15
|
+
export class PostgresQueueManagerQueries extends PostgresQueueManagerGroupQueries {
|
|
16
16
|
getJobIndex() {
|
|
17
17
|
return this.postgresSnapshot.locations();
|
|
18
18
|
}
|
|
@@ -95,6 +95,7 @@ export class QueueManagerControl extends QueueManagerQueries {
|
|
|
95
95
|
this.perQueueMetrics.delete(queue);
|
|
96
96
|
this.telemetryJournal.clearQueue(queue);
|
|
97
97
|
this.storage?.deleteQueueState(queue);
|
|
98
|
+
this.storage?.deleteGroupState(queue);
|
|
98
99
|
}
|
|
99
100
|
listQueues() {
|
|
100
101
|
return Array.from(this.queueNamesCache);
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import type { Job, JobId, JobInput, JobLock } from '../../domain/types/job';
|
|
2
2
|
import type { AtomicFlowBatchInput, AtomicFlowBatchResult } from '../../domain/types/flow';
|
|
3
|
+
import type { GroupPullOptions } from '../../domain/types/group';
|
|
3
4
|
import { QueueManagerState } from './state';
|
|
4
5
|
export declare class QueueManagerDelivery extends QueueManagerState {
|
|
5
6
|
push(queue: string, input: JobInput): Promise<Job>;
|
|
6
7
|
pushBatch(queue: string, inputs: JobInput[]): Promise<JobId[]>;
|
|
7
8
|
pushFlow(batch: AtomicFlowBatchInput): Promise<AtomicFlowBatchResult>;
|
|
8
|
-
pull(queue: string, timeoutMs?: number, signal?: AbortSignal): Promise<Job | null>;
|
|
9
|
-
pullWithLock(queue: string, owner: string, timeoutMs?: number, lockTtl?: number, signal?: AbortSignal): Promise<{
|
|
9
|
+
pull(queue: string, timeoutMs?: number, signal?: AbortSignal, groupOptions?: GroupPullOptions): Promise<Job | null>;
|
|
10
|
+
pullWithLock(queue: string, owner: string, timeoutMs?: number, lockTtl?: number, signal?: AbortSignal, groupOptions?: GroupPullOptions): Promise<{
|
|
10
11
|
job: Job | null;
|
|
11
12
|
token: string | null;
|
|
12
13
|
}>;
|
|
13
|
-
pullBatch(queue: string, count: number, timeoutMs?: number, signal?: AbortSignal): Promise<Job[]>;
|
|
14
|
-
pullBatchWithLock(queue: string, count: number, owner: string, timeoutMs?: number, lockTtl?: number, signal?: AbortSignal): Promise<{
|
|
14
|
+
pullBatch(queue: string, count: number, timeoutMs?: number, signal?: AbortSignal, groupOptions?: GroupPullOptions): Promise<Job[]>;
|
|
15
|
+
pullBatchWithLock(queue: string, count: number, owner: string, timeoutMs?: number, lockTtl?: number, signal?: AbortSignal, groupOptions?: GroupPullOptions): Promise<{
|
|
15
16
|
jobs: Job[];
|
|
16
17
|
tokens: string[];
|
|
17
18
|
}>;
|
|
@@ -20,29 +20,36 @@ export class QueueManagerDelivery extends QueueManagerState {
|
|
|
20
20
|
async pushFlow(batch) {
|
|
21
21
|
return pushFlowBatch(batch, this.contextFactory.getPushContext());
|
|
22
22
|
}
|
|
23
|
-
async pull(queue, timeoutMs = 0, signal) {
|
|
24
|
-
const job = await pullJob(queue, timeoutMs, this.contextFactory.getPullContext(), signal);
|
|
23
|
+
async pull(queue, timeoutMs = 0, signal, groupOptions) {
|
|
24
|
+
const job = await pullJob(queue, timeoutMs, this.contextFactory.getPullContext(), signal, groupOptions);
|
|
25
25
|
if (job)
|
|
26
26
|
this.scheduleJobTimeout(job);
|
|
27
27
|
return job;
|
|
28
28
|
}
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
// oxlint-disable-next-line max-params -- public API includes cancellation and lock policy
|
|
30
|
+
async pullWithLock(queue, owner, timeoutMs = 0, lockTtl = DEFAULT_LOCK_TTL, signal, groupOptions) {
|
|
31
|
+
const job = await pullJob(queue, timeoutMs, this.contextFactory.getPullContext(), signal, groupOptions);
|
|
31
32
|
if (!job)
|
|
32
33
|
return { job: null, token: null };
|
|
33
34
|
const token = lockMgr.createLock(job.id, owner, this.contextFactory.getLockContext(), lockTtl);
|
|
34
35
|
this.scheduleJobTimeout(job);
|
|
35
36
|
return { job, token };
|
|
36
37
|
}
|
|
37
|
-
async pullBatch(queue, count, timeoutMs = 0, signal) {
|
|
38
|
-
const jobs = await pullJobBatch(queue, count, timeoutMs, this.contextFactory.getPullContext(),
|
|
38
|
+
async pullBatch(queue, count, timeoutMs = 0, signal, groupOptions) {
|
|
39
|
+
const jobs = await pullJobBatch(queue, count, timeoutMs, this.contextFactory.getPullContext(), {
|
|
40
|
+
signal,
|
|
41
|
+
group: groupOptions,
|
|
42
|
+
});
|
|
39
43
|
for (const job of jobs)
|
|
40
44
|
this.scheduleJobTimeout(job);
|
|
41
45
|
return jobs;
|
|
42
46
|
}
|
|
43
47
|
// oxlint-disable-next-line max-params -- public API includes cancellation and lock policy
|
|
44
|
-
async pullBatchWithLock(queue, count, owner, timeoutMs = 0, lockTtl = DEFAULT_LOCK_TTL, signal) {
|
|
45
|
-
const jobs = await pullJobBatch(queue, count, timeoutMs, this.contextFactory.getPullContext(),
|
|
48
|
+
async pullBatchWithLock(queue, count, owner, timeoutMs = 0, lockTtl = DEFAULT_LOCK_TTL, signal, groupOptions) {
|
|
49
|
+
const jobs = await pullJobBatch(queue, count, timeoutMs, this.contextFactory.getPullContext(), {
|
|
50
|
+
signal,
|
|
51
|
+
group: groupOptions,
|
|
52
|
+
});
|
|
46
53
|
const tokens = jobs.map((job) => lockMgr.createLock(job.id, owner, this.contextFactory.getLockContext(), lockTtl) ?? '');
|
|
47
54
|
for (const job of jobs)
|
|
48
55
|
this.scheduleJobTimeout(job);
|
|
@@ -1,7 +1,18 @@
|
|
|
1
1
|
import type { Job, JobId } from '../../domain/types/job';
|
|
2
2
|
import type { DlqEntry, DlqFilter, DlqStats } from '../../domain/types/dlq';
|
|
3
3
|
import { QueueManagerControl } from './control';
|
|
4
|
+
import { type GroupRateLimitOverride } from '../../domain/types/group';
|
|
4
5
|
export declare class QueueManagerLimits extends QueueManagerControl {
|
|
6
|
+
getGroupJobsCount(queue: string, groupId: string): number | Promise<number>;
|
|
7
|
+
getGroupsJobsCount(queue: string): number | Promise<number>;
|
|
8
|
+
getGroupActiveCount(queue: string, groupId: string): number | Promise<number>;
|
|
9
|
+
setGroupRateLimit(queue: string, groupId: string, max: number, duration: number): void | Promise<void>;
|
|
10
|
+
getGroupRateLimit(queue: string, groupId: string): GroupRateLimitOverride | null | Promise<GroupRateLimitOverride | null>;
|
|
11
|
+
removeGroupRateLimit(queue: string, groupId: string): number | Promise<number>;
|
|
12
|
+
getGroupRateLimitTtl(queue: string, groupId: string, maxJobs?: number): number | Promise<number>;
|
|
13
|
+
setGroupConcurrency(queue: string, groupId: string, concurrency: number): void | Promise<void>;
|
|
14
|
+
getGroupConcurrency(queue: string, groupId: string): number | null | Promise<number | null>;
|
|
15
|
+
removeGroupConcurrency(queue: string, groupId: string): number | Promise<number>;
|
|
5
16
|
getCountsPerPriority(queue: string): Record<number, number>;
|
|
6
17
|
getJobs(queue: string, options?: {
|
|
7
18
|
state?: string | string[];
|