bunqueue 2.8.33 → 2.8.34
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/application/operations/jobManagement.d.ts +0 -2
- package/dist/application/operations/jobManagement.js +0 -14
- package/dist/application/operations/jobPromotion.d.ts +7 -0
- package/dist/application/operations/jobPromotion.js +58 -0
- package/dist/application/queueManager.d.ts +1 -0
- package/dist/application/queueManager.js +5 -1
- package/dist/client/queue/operations/management.js +1 -11
- package/dist/domain/queue/shard.d.ts +2 -0
- package/dist/domain/queue/shard.js +5 -0
- package/dist/infrastructure/server/handlers/advanced.js +1 -8
- package/package.json +2 -1
|
@@ -29,8 +29,6 @@ export declare function updateJobProgress(jobId: JobId, progress: number, ctx: J
|
|
|
29
29
|
export declare function updateJobData(jobId: JobId, data: unknown, ctx: JobManagementContext): Promise<boolean>;
|
|
30
30
|
/** Change job priority */
|
|
31
31
|
export declare function changeJobPriority(jobId: JobId, priority: number, ctx: JobManagementContext, lifo?: boolean): Promise<boolean>;
|
|
32
|
-
/** Promote delayed job to waiting */
|
|
33
|
-
export declare function promoteJob(jobId: JobId, ctx: JobManagementContext): Promise<boolean>;
|
|
34
32
|
/** Move active job back to delayed */
|
|
35
33
|
export declare function moveJobToDelayed(jobId: JobId, delay: number, ctx: JobManagementContext): Promise<boolean>;
|
|
36
34
|
/** Discard job to DLQ */
|
|
@@ -162,20 +162,6 @@ export async function changeJobPriority(jobId, priority, ctx, lifo) {
|
|
|
162
162
|
return q.updatePriority(jobId, priority, lifo);
|
|
163
163
|
});
|
|
164
164
|
}
|
|
165
|
-
/** Promote delayed job to waiting */
|
|
166
|
-
export async function promoteJob(jobId, ctx) {
|
|
167
|
-
const location = ctx.jobIndex.get(jobId);
|
|
168
|
-
if (location?.type !== 'queue')
|
|
169
|
-
return false;
|
|
170
|
-
return withWriteLock(ctx.shardLocks[location.shardIdx], () => {
|
|
171
|
-
const q = ctx.shards[location.shardIdx].getQueue(location.queueName);
|
|
172
|
-
const job = q.find(jobId);
|
|
173
|
-
if (!job || job.runAt <= Date.now())
|
|
174
|
-
return false;
|
|
175
|
-
q.updateRunAt(jobId, Date.now());
|
|
176
|
-
return true;
|
|
177
|
-
});
|
|
178
|
-
}
|
|
179
165
|
/** Move active job back to delayed */
|
|
180
166
|
export async function moveJobToDelayed(jobId, delay, ctx) {
|
|
181
167
|
const location = ctx.jobIndex.get(jobId);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** Delayed-job promotion operations shared by embedded and server modes. */
|
|
2
|
+
import type { JobId } from '../../domain/types/job';
|
|
3
|
+
import type { JobManagementContext } from './jobManagement';
|
|
4
|
+
/** Promote one delayed job and persist the transition before resolving. */
|
|
5
|
+
export declare function promoteJob(jobId: JobId, ctx: JobManagementContext): Promise<boolean>;
|
|
6
|
+
/** Promote the oldest delayed jobs from the live shard, never an eventual SQL listing. */
|
|
7
|
+
export declare function promoteJobs(queueName: string, count: number | undefined, ctx: JobManagementContext): Promise<number>;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/** Delayed-job promotion operations shared by embedded and server modes. */
|
|
2
|
+
import { shardIndex } from '../../shared/hash';
|
|
3
|
+
import { withWriteLock } from '../../shared/lock';
|
|
4
|
+
function compareOldestFirst(a, b) {
|
|
5
|
+
if (a.createdAt !== b.createdAt)
|
|
6
|
+
return a.createdAt - b.createdAt;
|
|
7
|
+
if (a.id === b.id)
|
|
8
|
+
return 0;
|
|
9
|
+
return a.id < b.id ? -1 : 1;
|
|
10
|
+
}
|
|
11
|
+
/** Promote one delayed job and persist the transition before resolving. */
|
|
12
|
+
export async function promoteJob(jobId, ctx) {
|
|
13
|
+
const location = ctx.jobIndex.get(jobId);
|
|
14
|
+
if (location?.type !== 'queue')
|
|
15
|
+
return false;
|
|
16
|
+
const promotedAt = Date.now();
|
|
17
|
+
const success = await withWriteLock(ctx.shardLocks[location.shardIdx], () => {
|
|
18
|
+
const shard = ctx.shards[location.shardIdx];
|
|
19
|
+
const queue = shard.getQueue(location.queueName);
|
|
20
|
+
const job = queue.find(jobId);
|
|
21
|
+
if (!job || job.runAt <= promotedAt || !queue.updateRunAt(jobId, promotedAt))
|
|
22
|
+
return false;
|
|
23
|
+
shard.promoteDelayed(jobId);
|
|
24
|
+
shard.notify(location.queueName);
|
|
25
|
+
return true;
|
|
26
|
+
});
|
|
27
|
+
if (success)
|
|
28
|
+
ctx.storage?.updateRunAt(jobId, promotedAt);
|
|
29
|
+
return success;
|
|
30
|
+
}
|
|
31
|
+
/** Promote the oldest delayed jobs from the live shard, never an eventual SQL listing. */
|
|
32
|
+
export async function promoteJobs(queueName, count, ctx) {
|
|
33
|
+
const idx = shardIndex(queueName);
|
|
34
|
+
const promotedAt = Date.now();
|
|
35
|
+
const promotedIds = await withWriteLock(ctx.shardLocks[idx], () => {
|
|
36
|
+
const shard = ctx.shards[idx];
|
|
37
|
+
const queue = shard.getQueue(queueName);
|
|
38
|
+
const delayed = queue
|
|
39
|
+
.values()
|
|
40
|
+
.filter((job) => job.runAt > promotedAt)
|
|
41
|
+
.sort(compareOldestFirst);
|
|
42
|
+
const limit = count === undefined ? delayed.length : Math.max(0, Math.floor(count));
|
|
43
|
+
const ids = [];
|
|
44
|
+
for (let i = 0; i < Math.min(limit, delayed.length); i++) {
|
|
45
|
+
const id = delayed[i].id;
|
|
46
|
+
if (!queue.updateRunAt(id, promotedAt))
|
|
47
|
+
continue;
|
|
48
|
+
shard.promoteDelayed(id);
|
|
49
|
+
ids.push(id);
|
|
50
|
+
}
|
|
51
|
+
if (ids.length > 0)
|
|
52
|
+
shard.notifyBatch(queueName, ids.length);
|
|
53
|
+
return ids;
|
|
54
|
+
});
|
|
55
|
+
for (const id of promotedIds)
|
|
56
|
+
ctx.storage?.updateRunAt(id, promotedAt);
|
|
57
|
+
return promotedIds.length;
|
|
58
|
+
}
|
|
@@ -237,6 +237,7 @@ export declare class QueueManager {
|
|
|
237
237
|
updateJobData(jobId: JobId, data: unknown): Promise<boolean>;
|
|
238
238
|
changePriority(jobId: JobId, priority: number, lifo?: boolean): Promise<boolean>;
|
|
239
239
|
promote(jobId: JobId): Promise<boolean>;
|
|
240
|
+
promoteJobs(queue: string, count?: number): Promise<number>;
|
|
240
241
|
moveToDelayed(jobId: JobId, delay: number): Promise<boolean>;
|
|
241
242
|
changeDelay(jobId: JobId, delay: number): Promise<boolean>;
|
|
242
243
|
moveActiveToWait(jobId: JobId): Promise<boolean>;
|
|
@@ -17,6 +17,7 @@ import { pullJob, pullJobBatch } from './operations/pull';
|
|
|
17
17
|
import { ackJob, ackJobBatch, ackJobBatchWithResults, failJob } from './operations/ack';
|
|
18
18
|
import * as queueControl from './operations/queueControl';
|
|
19
19
|
import * as jobMgmt from './operations/jobManagement';
|
|
20
|
+
import * as jobPromotion from './operations/jobPromotion';
|
|
20
21
|
import * as jobTransitions from './operations/jobStateTransitions';
|
|
21
22
|
import * as queryOps from './operations/queryOperations';
|
|
22
23
|
import * as dlqOps from './dlqManager';
|
|
@@ -975,7 +976,10 @@ export class QueueManager {
|
|
|
975
976
|
return jobMgmt.changeJobPriority(jobId, priority, this.contextFactory.getJobMgmtContext(), lifo);
|
|
976
977
|
}
|
|
977
978
|
async promote(jobId) {
|
|
978
|
-
return
|
|
979
|
+
return jobPromotion.promoteJob(jobId, this.contextFactory.getJobMgmtContext());
|
|
980
|
+
}
|
|
981
|
+
async promoteJobs(queue, count) {
|
|
982
|
+
return jobPromotion.promoteJobs(queue, count, this.contextFactory.getJobMgmtContext());
|
|
979
983
|
}
|
|
980
984
|
async moveToDelayed(jobId, delay) {
|
|
981
985
|
// moveToDelayed and changeDelay share identical routing in this engine: a job
|
|
@@ -93,17 +93,7 @@ export async function cleanAsync(ctx, grace, limit, type) {
|
|
|
93
93
|
/** Promote delayed jobs to waiting */
|
|
94
94
|
export async function promoteJobs(ctx, opts) {
|
|
95
95
|
if (ctx.embedded) {
|
|
96
|
-
|
|
97
|
-
const manager = getSharedManager();
|
|
98
|
-
const jobs = manager.getJobs(ctx.name, { state: 'delayed' });
|
|
99
|
-
const count = opts?.count ?? jobs.length;
|
|
100
|
-
let promoted = 0;
|
|
101
|
-
for (let i = 0; i < Math.min(count, jobs.length); i++) {
|
|
102
|
-
const success = await manager.promote(jobs[i].id);
|
|
103
|
-
if (success)
|
|
104
|
-
promoted++;
|
|
105
|
-
}
|
|
106
|
-
return promoted;
|
|
96
|
+
return getSharedManager().promoteJobs(ctx.name, opts?.count);
|
|
107
97
|
}
|
|
108
98
|
const response = await ctx.tcp.send({
|
|
109
99
|
cmd: 'PromoteJobs',
|
|
@@ -116,6 +116,8 @@ export declare class Shard {
|
|
|
116
116
|
};
|
|
117
117
|
incrementQueued(jobId: JobId, isDelayed: boolean, createdAt?: number, queue?: string, runAt?: number): void;
|
|
118
118
|
decrementQueued(jobId: JobId): void;
|
|
119
|
+
/** Remove a promoted job from delayed tracking without changing queue depth. */
|
|
120
|
+
promoteDelayed(jobId: JobId): void;
|
|
119
121
|
incrementDlq(): void;
|
|
120
122
|
decrementDlq(count?: number): void;
|
|
121
123
|
refreshDelayedCount(now: number): void;
|
|
@@ -302,6 +302,11 @@ export class Shard {
|
|
|
302
302
|
decrementQueued(jobId) {
|
|
303
303
|
this.counters.decrementQueued(jobId);
|
|
304
304
|
}
|
|
305
|
+
/** Remove a promoted job from delayed tracking without changing queue depth. */
|
|
306
|
+
promoteDelayed(jobId) {
|
|
307
|
+
this.temporalManager.removeDelayed(jobId);
|
|
308
|
+
this.counters.syncDelayedCount();
|
|
309
|
+
}
|
|
305
310
|
incrementDlq() {
|
|
306
311
|
this.counters.incrementDlq();
|
|
307
312
|
}
|
|
@@ -281,14 +281,7 @@ export async function handleMoveToWait(cmd, ctx, reqId) {
|
|
|
281
281
|
}
|
|
282
282
|
/** Handle PromoteJobs command - promote all delayed jobs in a queue */
|
|
283
283
|
export async function handlePromoteJobs(cmd, ctx, reqId) {
|
|
284
|
-
const
|
|
285
|
-
const limit = cmd.count ?? delayed.length;
|
|
286
|
-
let count = 0;
|
|
287
|
-
for (let i = 0; i < Math.min(limit, delayed.length); i++) {
|
|
288
|
-
const success = await ctx.queueManager.promote(delayed[i].id);
|
|
289
|
-
if (success)
|
|
290
|
-
count++;
|
|
291
|
-
}
|
|
284
|
+
const count = await ctx.queueManager.promoteJobs(cmd.queue, cmd.count);
|
|
292
285
|
return { ok: true, count, reqId };
|
|
293
286
|
}
|
|
294
287
|
// ============ Flow Dependency Commands ============
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bunqueue",
|
|
3
|
-
"version": "2.8.
|
|
3
|
+
"version": "2.8.34",
|
|
4
4
|
"description": "High-performance job queue for Bun & AI agents. SQLite persistence, cron scheduling, priorities, retries, DLQ, webhooks, native MCP server. Zero external infrastructure.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/main.js",
|
|
@@ -57,6 +57,7 @@
|
|
|
57
57
|
"build": "bun build --compile --minify src/main.ts --outfile dist/bunqueue",
|
|
58
58
|
"build:lib": "tsc -p tsconfig.build.json",
|
|
59
59
|
"test": "BUNQUEUE_EMBEDDED=1 bun test",
|
|
60
|
+
"test:sandbox": "bun run scripts/test-sandbox.ts",
|
|
60
61
|
"bench": "bun run bench/throughput.ts && bun run bench/latency.ts",
|
|
61
62
|
"bench:throughput": "bun run bench/throughput.ts",
|
|
62
63
|
"bench:latency": "bun run bench/latency.ts",
|