bunqueue 1.6.2 → 1.6.4
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 +70 -0
- package/dist/application/dlqManager.d.ts +2 -0
- package/dist/application/dlqManager.d.ts.map +1 -1
- package/dist/application/dlqManager.js +21 -3
- package/dist/application/dlqManager.js.map +1 -1
- package/dist/application/operations/ack.js +2 -2
- package/dist/application/operations/ack.js.map +1 -1
- package/dist/application/operations/jobManagement.d.ts.map +1 -1
- package/dist/application/operations/jobManagement.js +5 -3
- package/dist/application/operations/jobManagement.js.map +1 -1
- package/dist/application/queueManager.d.ts.map +1 -1
- package/dist/application/queueManager.js +31 -6
- package/dist/application/queueManager.js.map +1 -1
- package/dist/client/index.d.ts +2 -0
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +1 -0
- package/dist/client/index.js.map +1 -1
- package/dist/client/manager.d.ts +2 -0
- package/dist/client/manager.d.ts.map +1 -1
- package/dist/client/manager.js +8 -1
- package/dist/client/manager.js.map +1 -1
- package/dist/client/sandboxedWorker.d.ts +90 -0
- package/dist/client/sandboxedWorker.d.ts.map +1 -0
- package/dist/client/sandboxedWorker.js +299 -0
- package/dist/client/sandboxedWorker.js.map +1 -0
- package/dist/infrastructure/persistence/schema.d.ts +2 -2
- package/dist/infrastructure/persistence/schema.d.ts.map +1 -1
- package/dist/infrastructure/persistence/schema.js +4 -6
- package/dist/infrastructure/persistence/schema.js.map +1 -1
- package/dist/infrastructure/persistence/sqlite.d.ts +9 -0
- package/dist/infrastructure/persistence/sqlite.d.ts.map +1 -1
- package/dist/infrastructure/persistence/sqlite.js +43 -1
- package/dist/infrastructure/persistence/sqlite.js.map +1 -1
- package/dist/infrastructure/persistence/statements.d.ts +1 -1
- package/dist/infrastructure/persistence/statements.d.ts.map +1 -1
- package/dist/infrastructure/persistence/statements.js +4 -1
- package/dist/infrastructure/persistence/statements.js.map +1 -1
- package/dist/mcp/index.d.ts +22 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +574 -0
- package/dist/mcp/index.js.map +1 -0
- package/package.json +7 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5C,YAAY,EACV,GAAG,EACH,UAAU,EACV,YAAY,EACZ,aAAa,EACb,SAAS,EACT,WAAW,EACX,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,aAAa,GACd,MAAM,SAAS,CAAC;AACjB,YAAY,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5C,YAAY,EACV,GAAG,EACH,UAAU,EACV,YAAY,EACZ,aAAa,EACb,SAAS,EACT,WAAW,EACX,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,aAAa,GACd,MAAM,SAAS,CAAC;AACjB,YAAY,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AACnD,YAAY,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC"}
|
package/dist/client/index.js
CHANGED
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
*/
|
|
21
21
|
export { Queue } from './queue';
|
|
22
22
|
export { Worker } from './worker';
|
|
23
|
+
export { SandboxedWorker } from './sandboxedWorker';
|
|
23
24
|
export { QueueEvents } from './events';
|
|
24
25
|
export { QueueGroup } from './queueGroup';
|
|
25
26
|
export { FlowProducer } from './flow';
|
package/dist/client/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC"}
|
package/dist/client/manager.d.ts
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
* Shared QueueManager singleton
|
|
3
3
|
*/
|
|
4
4
|
import { QueueManager } from '../application/queueManager';
|
|
5
|
+
/** Shared manager type export */
|
|
6
|
+
export type SharedManager = QueueManager;
|
|
5
7
|
/** Get shared QueueManager instance */
|
|
6
8
|
export declare function getSharedManager(): QueueManager;
|
|
7
9
|
/** Shutdown shared manager */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/client/manager.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/client/manager.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAE3D,iCAAiC;AACjC,MAAM,MAAM,aAAa,GAAG,YAAY,CAAC;AASzC,uCAAuC;AACvC,wBAAgB,gBAAgB,IAAI,YAAY,CAM/C;AAED,8BAA8B;AAC9B,wBAAgB,eAAe,IAAI,IAAI,CAKtC"}
|
package/dist/client/manager.js
CHANGED
|
@@ -3,9 +3,16 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { QueueManager } from '../application/queueManager';
|
|
5
5
|
let instance = null;
|
|
6
|
+
/** Get data path from environment */
|
|
7
|
+
function getDataPath() {
|
|
8
|
+
return process.env.DATA_PATH ?? process.env.SQLITE_PATH;
|
|
9
|
+
}
|
|
6
10
|
/** Get shared QueueManager instance */
|
|
7
11
|
export function getSharedManager() {
|
|
8
|
-
|
|
12
|
+
if (!instance) {
|
|
13
|
+
const dataPath = getDataPath();
|
|
14
|
+
instance = new QueueManager({ dataPath });
|
|
15
|
+
}
|
|
9
16
|
return instance;
|
|
10
17
|
}
|
|
11
18
|
/** Shutdown shared manager */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/client/manager.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/client/manager.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAK3D,IAAI,QAAQ,GAAwB,IAAI,CAAC;AAEzC,qCAAqC;AACrC,SAAS,WAAW;IAClB,OAAO,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;AAC1D,CAAC;AAED,uCAAuC;AACvC,MAAM,UAAU,gBAAgB;IAC9B,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAC;QAC/B,QAAQ,GAAG,IAAI,YAAY,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC5C,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,8BAA8B;AAC9B,MAAM,UAAU,eAAe;IAC7B,IAAI,QAAQ,EAAE,CAAC;QACb,QAAQ,CAAC,QAAQ,EAAE,CAAC;QACpB,QAAQ,GAAG,IAAI,CAAC;IAClB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sandboxed Worker
|
|
3
|
+
* Runs job processors in isolated Bun Worker processes
|
|
4
|
+
*/
|
|
5
|
+
import { type SharedManager } from './manager';
|
|
6
|
+
/** Sandboxed worker configuration */
|
|
7
|
+
export interface SandboxedWorkerOptions {
|
|
8
|
+
/** Path to processor file (must export default async function) */
|
|
9
|
+
processor: string;
|
|
10
|
+
/** Number of worker processes (default: 1) */
|
|
11
|
+
concurrency?: number;
|
|
12
|
+
/** Max memory per worker in MB - uses smol mode if <= 64 (default: 256) */
|
|
13
|
+
maxMemory?: number;
|
|
14
|
+
/** Job timeout in ms (default: 30000) */
|
|
15
|
+
timeout?: number;
|
|
16
|
+
/** Auto-restart crashed workers (default: true) */
|
|
17
|
+
autoRestart?: boolean;
|
|
18
|
+
/** Max restarts before giving up (default: 10) */
|
|
19
|
+
maxRestarts?: number;
|
|
20
|
+
/** Poll interval when no workers are idle (default: 10ms) */
|
|
21
|
+
pollInterval?: number;
|
|
22
|
+
/** Custom QueueManager (for testing, defaults to shared manager) */
|
|
23
|
+
manager?: SharedManager;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Sandboxed Worker - runs processors in isolated Bun Worker processes
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```typescript
|
|
30
|
+
* import { Queue, SandboxedWorker } from 'bunqueue/client';
|
|
31
|
+
*
|
|
32
|
+
* const queue = new Queue('cpu-intensive');
|
|
33
|
+
*
|
|
34
|
+
* // Create processor file: processor.ts
|
|
35
|
+
* // export default async (job) => {
|
|
36
|
+
* // const result = heavyComputation(job.data);
|
|
37
|
+
* // return result;
|
|
38
|
+
* // };
|
|
39
|
+
*
|
|
40
|
+
* const worker = new SandboxedWorker('cpu-intensive', {
|
|
41
|
+
* processor: './processor.ts',
|
|
42
|
+
* concurrency: 4,
|
|
43
|
+
* timeout: 60000,
|
|
44
|
+
* });
|
|
45
|
+
*
|
|
46
|
+
* await worker.start();
|
|
47
|
+
* // Workers process jobs in isolated processes
|
|
48
|
+
* // If one crashes, others continue working
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
export declare class SandboxedWorker {
|
|
52
|
+
private readonly queueName;
|
|
53
|
+
private readonly options;
|
|
54
|
+
private readonly workers;
|
|
55
|
+
private running;
|
|
56
|
+
private pullPromise;
|
|
57
|
+
private wrapperPath;
|
|
58
|
+
private readonly manager;
|
|
59
|
+
constructor(queueName: string, options: SandboxedWorkerOptions);
|
|
60
|
+
/** Start the sandboxed worker pool */
|
|
61
|
+
start(): void;
|
|
62
|
+
/** Stop all workers gracefully */
|
|
63
|
+
stop(): Promise<void>;
|
|
64
|
+
/** Get worker pool stats */
|
|
65
|
+
getStats(): {
|
|
66
|
+
total: number;
|
|
67
|
+
busy: number;
|
|
68
|
+
idle: number;
|
|
69
|
+
restarts: number;
|
|
70
|
+
};
|
|
71
|
+
/** Create wrapper script file that loads the processor */
|
|
72
|
+
private createWrapperScript;
|
|
73
|
+
/** Spawn a single worker process */
|
|
74
|
+
private spawnWorker;
|
|
75
|
+
/** Main loop - pull jobs and dispatch to workers */
|
|
76
|
+
private pullLoop;
|
|
77
|
+
/** Dispatch job to a worker process */
|
|
78
|
+
private dispatchJob;
|
|
79
|
+
/** Handle message from worker */
|
|
80
|
+
private handleWorkerMessage;
|
|
81
|
+
/** Complete a job successfully */
|
|
82
|
+
private completeJob;
|
|
83
|
+
/** Fail a job */
|
|
84
|
+
private failJob;
|
|
85
|
+
/** Handle job timeout */
|
|
86
|
+
private handleJobTimeout;
|
|
87
|
+
/** Handle worker crash and potentially restart */
|
|
88
|
+
private handleWorkerCrash;
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=sandboxedWorker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sandboxedWorker.d.ts","sourceRoot":"","sources":["../../src/client/sandboxedWorker.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAoB,KAAK,aAAa,EAAE,MAAM,WAAW,CAAC;AAMjE,qCAAqC;AACrC,MAAM,WAAW,sBAAsB;IACrC,kEAAkE;IAClE,SAAS,EAAE,MAAM,CAAC;IAClB,8CAA8C;IAC9C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,2EAA2E;IAC3E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yCAAyC;IACzC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mDAAmD;IACnD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,kDAAkD;IAClD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6DAA6D;IAC7D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oEAAoE;IACpE,OAAO,CAAC,EAAE,aAAa,CAAC;CACzB;AA+BD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoD;IAC5E,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuB;IAC/C,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,WAAW,CAA8B;IACjD,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgB;gBAE5B,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,sBAAsB;IAc9D,sCAAsC;IACtC,KAAK,IAAI,IAAI;IAgBb,kCAAkC;IAC5B,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IA+B3B,4BAA4B;IAC5B,QAAQ,IAAI;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE;IAW3E,0DAA0D;IAC1D,OAAO,CAAC,mBAAmB;IA+C3B,oCAAoC;IACpC,OAAO,CAAC,WAAW;IAiCnB,oDAAoD;YACtC,QAAQ;IAkBtB,uCAAuC;IACvC,OAAO,CAAC,WAAW;IAsBnB,iCAAiC;IACjC,OAAO,CAAC,mBAAmB;IAkB3B,kCAAkC;IAClC,OAAO,CAAC,WAAW;IAiBnB,iBAAiB;IACjB,OAAO,CAAC,OAAO;IAiBf,yBAAyB;IACzB,OAAO,CAAC,gBAAgB;IAgBxB,kDAAkD;IAClD,OAAO,CAAC,iBAAiB;CAoB1B"}
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sandboxed Worker
|
|
3
|
+
* Runs job processors in isolated Bun Worker processes
|
|
4
|
+
*/
|
|
5
|
+
import { getSharedManager } from './manager';
|
|
6
|
+
import { join } from 'path';
|
|
7
|
+
import { writeFileSync, unlinkSync, existsSync, mkdirSync } from 'fs';
|
|
8
|
+
import { tmpdir } from 'os';
|
|
9
|
+
/**
|
|
10
|
+
* Sandboxed Worker - runs processors in isolated Bun Worker processes
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* import { Queue, SandboxedWorker } from 'bunqueue/client';
|
|
15
|
+
*
|
|
16
|
+
* const queue = new Queue('cpu-intensive');
|
|
17
|
+
*
|
|
18
|
+
* // Create processor file: processor.ts
|
|
19
|
+
* // export default async (job) => {
|
|
20
|
+
* // const result = heavyComputation(job.data);
|
|
21
|
+
* // return result;
|
|
22
|
+
* // };
|
|
23
|
+
*
|
|
24
|
+
* const worker = new SandboxedWorker('cpu-intensive', {
|
|
25
|
+
* processor: './processor.ts',
|
|
26
|
+
* concurrency: 4,
|
|
27
|
+
* timeout: 60000,
|
|
28
|
+
* });
|
|
29
|
+
*
|
|
30
|
+
* await worker.start();
|
|
31
|
+
* // Workers process jobs in isolated processes
|
|
32
|
+
* // If one crashes, others continue working
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export class SandboxedWorker {
|
|
36
|
+
queueName;
|
|
37
|
+
options;
|
|
38
|
+
workers = [];
|
|
39
|
+
running = false;
|
|
40
|
+
pullPromise = null;
|
|
41
|
+
wrapperPath = null;
|
|
42
|
+
manager;
|
|
43
|
+
constructor(queueName, options) {
|
|
44
|
+
this.queueName = queueName;
|
|
45
|
+
this.manager = options.manager ?? getSharedManager();
|
|
46
|
+
this.options = {
|
|
47
|
+
processor: options.processor,
|
|
48
|
+
concurrency: options.concurrency ?? 1,
|
|
49
|
+
maxMemory: options.maxMemory ?? 256,
|
|
50
|
+
timeout: options.timeout ?? 30000,
|
|
51
|
+
autoRestart: options.autoRestart ?? true,
|
|
52
|
+
maxRestarts: options.maxRestarts ?? 10,
|
|
53
|
+
pollInterval: options.pollInterval ?? 10,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
/** Start the sandboxed worker pool */
|
|
57
|
+
start() {
|
|
58
|
+
if (this.running)
|
|
59
|
+
return;
|
|
60
|
+
this.running = true;
|
|
61
|
+
// Create wrapper script for workers
|
|
62
|
+
this.wrapperPath = this.createWrapperScript();
|
|
63
|
+
// Spawn worker processes
|
|
64
|
+
for (let i = 0; i < this.options.concurrency; i++) {
|
|
65
|
+
this.spawnWorker(i);
|
|
66
|
+
}
|
|
67
|
+
// Start pulling jobs
|
|
68
|
+
this.pullPromise = this.pullLoop();
|
|
69
|
+
}
|
|
70
|
+
/** Stop all workers gracefully */
|
|
71
|
+
async stop() {
|
|
72
|
+
this.running = false;
|
|
73
|
+
// Clear all timeouts
|
|
74
|
+
for (const wp of this.workers) {
|
|
75
|
+
if (wp.timeoutId) {
|
|
76
|
+
clearTimeout(wp.timeoutId);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// Terminate all workers
|
|
80
|
+
for (const wp of this.workers) {
|
|
81
|
+
wp.worker.terminate();
|
|
82
|
+
}
|
|
83
|
+
this.workers.length = 0;
|
|
84
|
+
// Wait for pull loop to finish
|
|
85
|
+
if (this.pullPromise) {
|
|
86
|
+
await this.pullPromise;
|
|
87
|
+
}
|
|
88
|
+
// Cleanup wrapper script
|
|
89
|
+
if (this.wrapperPath && existsSync(this.wrapperPath)) {
|
|
90
|
+
try {
|
|
91
|
+
unlinkSync(this.wrapperPath);
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
// Ignore cleanup errors
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/** Get worker pool stats */
|
|
99
|
+
getStats() {
|
|
100
|
+
const busy = this.workers.filter((w) => w.busy).length;
|
|
101
|
+
const restarts = this.workers.reduce((sum, w) => sum + w.restarts, 0);
|
|
102
|
+
return {
|
|
103
|
+
total: this.workers.length,
|
|
104
|
+
busy,
|
|
105
|
+
idle: this.workers.length - busy,
|
|
106
|
+
restarts,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
/** Create wrapper script file that loads the processor */
|
|
110
|
+
createWrapperScript() {
|
|
111
|
+
const processorPath = this.options.processor.startsWith('/')
|
|
112
|
+
? this.options.processor
|
|
113
|
+
: join(process.cwd(), this.options.processor);
|
|
114
|
+
const wrapperCode = `
|
|
115
|
+
// Sandboxed Worker Wrapper
|
|
116
|
+
const processor = (await import('${processorPath}')).default;
|
|
117
|
+
|
|
118
|
+
self.onmessage = async (event) => {
|
|
119
|
+
const { type, job } = event.data;
|
|
120
|
+
if (type !== 'job') return;
|
|
121
|
+
|
|
122
|
+
try {
|
|
123
|
+
const result = await processor({
|
|
124
|
+
id: job.id,
|
|
125
|
+
data: job.data,
|
|
126
|
+
queue: job.queue,
|
|
127
|
+
attempts: job.attempts,
|
|
128
|
+
progress: (value) => {
|
|
129
|
+
self.postMessage({ type: 'progress', jobId: job.id, progress: value });
|
|
130
|
+
},
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
self.postMessage({ type: 'result', jobId: job.id, result });
|
|
134
|
+
} catch (err) {
|
|
135
|
+
self.postMessage({
|
|
136
|
+
type: 'error',
|
|
137
|
+
jobId: job.id,
|
|
138
|
+
error: err instanceof Error ? err.message : String(err),
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
`;
|
|
143
|
+
// Write to temp file
|
|
144
|
+
const tempDir = join(tmpdir(), 'bunqueue-workers');
|
|
145
|
+
if (!existsSync(tempDir)) {
|
|
146
|
+
mkdirSync(tempDir, { recursive: true });
|
|
147
|
+
}
|
|
148
|
+
const wrapperPath = join(tempDir, `worker-${this.queueName}-${Date.now()}.ts`);
|
|
149
|
+
writeFileSync(wrapperPath, wrapperCode);
|
|
150
|
+
return wrapperPath;
|
|
151
|
+
}
|
|
152
|
+
/** Spawn a single worker process */
|
|
153
|
+
spawnWorker(index) {
|
|
154
|
+
if (!this.wrapperPath)
|
|
155
|
+
return;
|
|
156
|
+
const worker = new Worker(this.wrapperPath, {
|
|
157
|
+
smol: this.options.maxMemory <= 64,
|
|
158
|
+
});
|
|
159
|
+
const wp = {
|
|
160
|
+
worker,
|
|
161
|
+
busy: false,
|
|
162
|
+
currentJob: null,
|
|
163
|
+
restarts: this.workers[index]?.restarts ?? 0,
|
|
164
|
+
timeoutId: null,
|
|
165
|
+
};
|
|
166
|
+
// Handle messages from worker
|
|
167
|
+
worker.onmessage = (event) => {
|
|
168
|
+
this.handleWorkerMessage(wp, event.data);
|
|
169
|
+
};
|
|
170
|
+
// Handle worker errors/crashes
|
|
171
|
+
worker.onerror = (error) => {
|
|
172
|
+
console.error(`[SandboxedWorker] Worker ${index} error:`, error.message);
|
|
173
|
+
this.handleWorkerCrash(wp, index);
|
|
174
|
+
};
|
|
175
|
+
if (this.workers[index]) {
|
|
176
|
+
this.workers[index] = wp;
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
this.workers.push(wp);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
/** Main loop - pull jobs and dispatch to workers */
|
|
183
|
+
async pullLoop() {
|
|
184
|
+
while (this.running) {
|
|
185
|
+
// Find idle worker
|
|
186
|
+
const idleWorker = this.workers.find((w) => !w.busy);
|
|
187
|
+
if (!idleWorker) {
|
|
188
|
+
await Bun.sleep(this.options.pollInterval);
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
// Pull job from queue using manager
|
|
192
|
+
const job = await this.manager.pull(this.queueName, 1000);
|
|
193
|
+
if (!job)
|
|
194
|
+
continue;
|
|
195
|
+
// Dispatch to worker
|
|
196
|
+
this.dispatchJob(idleWorker, job);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
/** Dispatch job to a worker process */
|
|
200
|
+
dispatchJob(wp, job) {
|
|
201
|
+
wp.busy = true;
|
|
202
|
+
wp.currentJob = job;
|
|
203
|
+
// Set timeout
|
|
204
|
+
wp.timeoutId = setTimeout(() => {
|
|
205
|
+
this.handleJobTimeout(wp, job);
|
|
206
|
+
}, this.options.timeout);
|
|
207
|
+
// Send job to worker
|
|
208
|
+
const request = {
|
|
209
|
+
type: 'job',
|
|
210
|
+
job: {
|
|
211
|
+
id: String(job.id),
|
|
212
|
+
data: job.data,
|
|
213
|
+
queue: job.queue,
|
|
214
|
+
attempts: job.attempts,
|
|
215
|
+
},
|
|
216
|
+
};
|
|
217
|
+
wp.worker.postMessage(request);
|
|
218
|
+
}
|
|
219
|
+
/** Handle message from worker */
|
|
220
|
+
handleWorkerMessage(wp, msg) {
|
|
221
|
+
if (!wp.currentJob || msg.jobId !== String(wp.currentJob.id))
|
|
222
|
+
return;
|
|
223
|
+
switch (msg.type) {
|
|
224
|
+
case 'result':
|
|
225
|
+
this.completeJob(wp, msg.result);
|
|
226
|
+
break;
|
|
227
|
+
case 'error':
|
|
228
|
+
this.failJob(wp, msg.error ?? 'Unknown error');
|
|
229
|
+
break;
|
|
230
|
+
case 'progress':
|
|
231
|
+
if (msg.progress !== undefined) {
|
|
232
|
+
this.manager.updateProgress(wp.currentJob.id, msg.progress).catch(() => { });
|
|
233
|
+
}
|
|
234
|
+
break;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
/** Complete a job successfully */
|
|
238
|
+
completeJob(wp, result) {
|
|
239
|
+
if (wp.timeoutId) {
|
|
240
|
+
clearTimeout(wp.timeoutId);
|
|
241
|
+
wp.timeoutId = null;
|
|
242
|
+
}
|
|
243
|
+
if (wp.currentJob) {
|
|
244
|
+
const jobId = wp.currentJob.id;
|
|
245
|
+
this.manager.ack(jobId, result).catch((err) => {
|
|
246
|
+
console.error(`[SandboxedWorker] Failed to ack job ${jobId}:`, err);
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
wp.busy = false;
|
|
250
|
+
wp.currentJob = null;
|
|
251
|
+
}
|
|
252
|
+
/** Fail a job */
|
|
253
|
+
failJob(wp, error) {
|
|
254
|
+
if (wp.timeoutId) {
|
|
255
|
+
clearTimeout(wp.timeoutId);
|
|
256
|
+
wp.timeoutId = null;
|
|
257
|
+
}
|
|
258
|
+
if (wp.currentJob) {
|
|
259
|
+
const jobId = wp.currentJob.id;
|
|
260
|
+
this.manager.fail(jobId, error).catch((err) => {
|
|
261
|
+
console.error(`[SandboxedWorker] Failed to fail job ${jobId}:`, err);
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
wp.busy = false;
|
|
265
|
+
wp.currentJob = null;
|
|
266
|
+
}
|
|
267
|
+
/** Handle job timeout */
|
|
268
|
+
handleJobTimeout(wp, job) {
|
|
269
|
+
console.error(`[SandboxedWorker] Job ${job.id} timed out after ${this.options.timeout}ms`);
|
|
270
|
+
// Terminate the stuck worker
|
|
271
|
+
wp.worker.terminate();
|
|
272
|
+
// Fail the job
|
|
273
|
+
this.manager.fail(job.id, `Job timed out after ${this.options.timeout}ms`).catch(() => { });
|
|
274
|
+
// Restart worker if allowed
|
|
275
|
+
const index = this.workers.indexOf(wp);
|
|
276
|
+
if (index !== -1) {
|
|
277
|
+
this.handleWorkerCrash(wp, index);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
/** Handle worker crash and potentially restart */
|
|
281
|
+
handleWorkerCrash(wp, index) {
|
|
282
|
+
// Fail current job if any
|
|
283
|
+
if (wp.currentJob) {
|
|
284
|
+
this.manager.fail(wp.currentJob.id, 'Worker crashed').catch(() => { });
|
|
285
|
+
}
|
|
286
|
+
wp.busy = false;
|
|
287
|
+
wp.currentJob = null;
|
|
288
|
+
wp.restarts++;
|
|
289
|
+
// Check if we should restart
|
|
290
|
+
if (this.options.autoRestart && wp.restarts < this.options.maxRestarts && this.running) {
|
|
291
|
+
console.log(`[SandboxedWorker] Restarting worker ${index} (attempt ${wp.restarts})`);
|
|
292
|
+
this.spawnWorker(index);
|
|
293
|
+
}
|
|
294
|
+
else if (wp.restarts >= this.options.maxRestarts) {
|
|
295
|
+
console.error(`[SandboxedWorker] Worker ${index} exceeded max restarts (${this.options.maxRestarts})`);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
//# sourceMappingURL=sandboxedWorker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sandboxedWorker.js","sourceRoot":"","sources":["../../src/client/sandboxedWorker.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|
/** SQLite PRAGMA settings for optimal performance */
|
|
5
5
|
export declare const PRAGMA_SETTINGS = "\nPRAGMA journal_mode = WAL;\nPRAGMA synchronous = NORMAL;\nPRAGMA cache_size = -64000;\nPRAGMA temp_store = MEMORY;\nPRAGMA mmap_size = 268435456;\nPRAGMA page_size = 4096;\n";
|
|
6
6
|
/** Main schema creation */
|
|
7
|
-
export declare const SCHEMA = "\n-- Jobs table (using UUIDv7 for job IDs)\n-- Uses BLOB for data fields (MessagePack serialization for ~2-3x faster than JSON)\nCREATE TABLE IF NOT EXISTS jobs (\n id TEXT PRIMARY KEY,\n queue TEXT NOT NULL,\n data BLOB NOT NULL,\n priority INTEGER NOT NULL DEFAULT 0,\n created_at INTEGER NOT NULL,\n run_at INTEGER NOT NULL,\n started_at INTEGER,\n completed_at INTEGER,\n attempts INTEGER NOT NULL DEFAULT 0,\n max_attempts INTEGER NOT NULL DEFAULT 3,\n backoff INTEGER NOT NULL DEFAULT 1000,\n ttl INTEGER,\n timeout INTEGER,\n unique_key TEXT,\n custom_id TEXT,\n depends_on BLOB,\n parent_id TEXT,\n children_ids BLOB,\n tags BLOB,\n state TEXT NOT NULL DEFAULT 'waiting',\n lifo INTEGER NOT NULL DEFAULT 0,\n group_id TEXT,\n progress INTEGER DEFAULT 0,\n progress_msg TEXT,\n remove_on_complete INTEGER DEFAULT 0,\n remove_on_fail INTEGER DEFAULT 0,\n stall_timeout INTEGER,\n last_heartbeat INTEGER\n);\n\n-- Indexes for common queries\nCREATE INDEX IF NOT EXISTS idx_jobs_queue_state\n ON jobs(queue, state);\nCREATE INDEX IF NOT EXISTS idx_jobs_run_at\n ON jobs(run_at) WHERE state IN ('waiting', 'delayed');\nCREATE INDEX IF NOT EXISTS idx_jobs_unique\n ON jobs(queue, unique_key) WHERE unique_key IS NOT NULL;\nCREATE INDEX IF NOT EXISTS idx_jobs_custom_id\n ON jobs(custom_id) WHERE custom_id IS NOT NULL;\nCREATE INDEX IF NOT EXISTS idx_jobs_parent\n ON jobs(parent_id) WHERE parent_id IS NOT NULL;\n\n-- Job results storage (BLOB for MessagePack)\nCREATE TABLE IF NOT EXISTS job_results (\n job_id TEXT PRIMARY KEY,\n result BLOB,\n completed_at INTEGER NOT NULL\n);\n\n-- Dead letter queue (BLOB for MessagePack)\nCREATE TABLE IF NOT EXISTS dlq (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n job_id TEXT NOT NULL,\n queue TEXT NOT NULL,\n
|
|
7
|
+
export declare const SCHEMA = "\n-- Jobs table (using UUIDv7 for job IDs)\n-- Uses BLOB for data fields (MessagePack serialization for ~2-3x faster than JSON)\nCREATE TABLE IF NOT EXISTS jobs (\n id TEXT PRIMARY KEY,\n queue TEXT NOT NULL,\n data BLOB NOT NULL,\n priority INTEGER NOT NULL DEFAULT 0,\n created_at INTEGER NOT NULL,\n run_at INTEGER NOT NULL,\n started_at INTEGER,\n completed_at INTEGER,\n attempts INTEGER NOT NULL DEFAULT 0,\n max_attempts INTEGER NOT NULL DEFAULT 3,\n backoff INTEGER NOT NULL DEFAULT 1000,\n ttl INTEGER,\n timeout INTEGER,\n unique_key TEXT,\n custom_id TEXT,\n depends_on BLOB,\n parent_id TEXT,\n children_ids BLOB,\n tags BLOB,\n state TEXT NOT NULL DEFAULT 'waiting',\n lifo INTEGER NOT NULL DEFAULT 0,\n group_id TEXT,\n progress INTEGER DEFAULT 0,\n progress_msg TEXT,\n remove_on_complete INTEGER DEFAULT 0,\n remove_on_fail INTEGER DEFAULT 0,\n stall_timeout INTEGER,\n last_heartbeat INTEGER\n);\n\n-- Indexes for common queries\nCREATE INDEX IF NOT EXISTS idx_jobs_queue_state\n ON jobs(queue, state);\nCREATE INDEX IF NOT EXISTS idx_jobs_run_at\n ON jobs(run_at) WHERE state IN ('waiting', 'delayed');\nCREATE INDEX IF NOT EXISTS idx_jobs_unique\n ON jobs(queue, unique_key) WHERE unique_key IS NOT NULL;\nCREATE INDEX IF NOT EXISTS idx_jobs_custom_id\n ON jobs(custom_id) WHERE custom_id IS NOT NULL;\nCREATE INDEX IF NOT EXISTS idx_jobs_parent\n ON jobs(parent_id) WHERE parent_id IS NOT NULL;\n\n-- Job results storage (BLOB for MessagePack)\nCREATE TABLE IF NOT EXISTS job_results (\n job_id TEXT PRIMARY KEY,\n result BLOB,\n completed_at INTEGER NOT NULL\n);\n\n-- Dead letter queue (BLOB for MessagePack - stores full DlqEntry)\nCREATE TABLE IF NOT EXISTS dlq (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n job_id TEXT NOT NULL,\n queue TEXT NOT NULL,\n entry BLOB NOT NULL,\n entered_at INTEGER NOT NULL\n);\n\nCREATE INDEX IF NOT EXISTS idx_dlq_queue ON dlq(queue);\nCREATE INDEX IF NOT EXISTS idx_dlq_job_id ON dlq(job_id);\n\n-- Cron jobs (BLOB for MessagePack)\nCREATE TABLE IF NOT EXISTS cron_jobs (\n name TEXT PRIMARY KEY,\n queue TEXT NOT NULL,\n data BLOB NOT NULL,\n schedule TEXT,\n repeat_every INTEGER,\n priority INTEGER NOT NULL DEFAULT 0,\n next_run INTEGER NOT NULL,\n executions INTEGER NOT NULL DEFAULT 0,\n max_limit INTEGER\n);\n\n-- Queue state persistence (optional)\nCREATE TABLE IF NOT EXISTS queue_state (\n name TEXT PRIMARY KEY,\n paused INTEGER NOT NULL DEFAULT 0,\n rate_limit INTEGER,\n concurrency_limit INTEGER\n);\n";
|
|
8
8
|
/** Migration version table */
|
|
9
9
|
export declare const MIGRATION_TABLE = "\nCREATE TABLE IF NOT EXISTS migrations (\n version INTEGER PRIMARY KEY,\n applied_at INTEGER NOT NULL\n);\n";
|
|
10
10
|
/** Current schema version */
|
|
11
|
-
export declare const SCHEMA_VERSION =
|
|
11
|
+
export declare const SCHEMA_VERSION = 4;
|
|
12
12
|
/** All migrations in order */
|
|
13
13
|
export declare const MIGRATIONS: Record<number, string>;
|
|
14
14
|
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/persistence/schema.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,qDAAqD;AACrD,eAAO,MAAM,eAAe,oLAO3B,CAAC;AAEF,2BAA2B;AAC3B,eAAO,MAAM,MAAM,
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/persistence/schema.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,qDAAqD;AACrD,eAAO,MAAM,eAAe,oLAO3B,CAAC;AAEF,2BAA2B;AAC3B,eAAO,MAAM,MAAM,glFAqFlB,CAAC;AAEF,8BAA8B;AAC9B,eAAO,MAAM,eAAe,uHAK3B,CAAC;AAEF,6BAA6B;AAC7B,eAAO,MAAM,cAAc,IAAI,CAAC;AAEhC,8BAA8B;AAC9B,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAE7C,CAAC"}
|
|
@@ -64,15 +64,13 @@ CREATE TABLE IF NOT EXISTS job_results (
|
|
|
64
64
|
completed_at INTEGER NOT NULL
|
|
65
65
|
);
|
|
66
66
|
|
|
67
|
-
-- Dead letter queue (BLOB for MessagePack)
|
|
67
|
+
-- Dead letter queue (BLOB for MessagePack - stores full DlqEntry)
|
|
68
68
|
CREATE TABLE IF NOT EXISTS dlq (
|
|
69
69
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
70
70
|
job_id TEXT NOT NULL,
|
|
71
71
|
queue TEXT NOT NULL,
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
failed_at INTEGER NOT NULL,
|
|
75
|
-
attempts INTEGER NOT NULL
|
|
72
|
+
entry BLOB NOT NULL,
|
|
73
|
+
entered_at INTEGER NOT NULL
|
|
76
74
|
);
|
|
77
75
|
|
|
78
76
|
CREATE INDEX IF NOT EXISTS idx_dlq_queue ON dlq(queue);
|
|
@@ -107,7 +105,7 @@ CREATE TABLE IF NOT EXISTS migrations (
|
|
|
107
105
|
);
|
|
108
106
|
`;
|
|
109
107
|
/** Current schema version */
|
|
110
|
-
export const SCHEMA_VERSION =
|
|
108
|
+
export const SCHEMA_VERSION = 4;
|
|
111
109
|
/** All migrations in order */
|
|
112
110
|
export const MIGRATIONS = {
|
|
113
111
|
1: SCHEMA,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../src/infrastructure/persistence/schema.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,qDAAqD;AACrD,MAAM,CAAC,MAAM,eAAe,GAAG;;;;;;;CAO9B,CAAC;AAEF,2BAA2B;AAC3B,MAAM,CAAC,MAAM,MAAM,GAAG
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../src/infrastructure/persistence/schema.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,qDAAqD;AACrD,MAAM,CAAC,MAAM,eAAe,GAAG;;;;;;;CAO9B,CAAC;AAEF,2BAA2B;AAC3B,MAAM,CAAC,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqFrB,CAAC;AAEF,8BAA8B;AAC9B,MAAM,CAAC,MAAM,eAAe,GAAG;;;;;CAK9B,CAAC;AAEF,6BAA6B;AAC7B,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC;AAEhC,8BAA8B;AAC9B,MAAM,CAAC,MAAM,UAAU,GAA2B;IAChD,CAAC,EAAE,MAAM;CACV,CAAC"}
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { type Job, type JobId } from '../../domain/types/job';
|
|
7
7
|
import type { CronJob } from '../../domain/types/cron';
|
|
8
|
+
import type { DlqEntry } from '../../domain/types/dlq';
|
|
8
9
|
/** SQLite configuration */
|
|
9
10
|
export interface SqliteConfig {
|
|
10
11
|
path: string;
|
|
@@ -37,6 +38,14 @@ export declare class SqliteStorage {
|
|
|
37
38
|
markActive(jobId: JobId, startedAt: number): void;
|
|
38
39
|
markCompleted(jobId: JobId, completedAt: number): void;
|
|
39
40
|
markFailed(job: Job, error: string | null): void;
|
|
41
|
+
/** Save DLQ entry with full metadata */
|
|
42
|
+
saveDlqEntry(entry: DlqEntry): void;
|
|
43
|
+
/** Delete DLQ entry by job ID */
|
|
44
|
+
deleteDlqEntry(jobId: JobId): void;
|
|
45
|
+
/** Clear all DLQ entries for a queue */
|
|
46
|
+
clearDlqQueue(queue: string): void;
|
|
47
|
+
/** Load all DLQ entries */
|
|
48
|
+
loadDlq(): Map<string, DlqEntry[]>;
|
|
40
49
|
updateForRetry(job: Job): void;
|
|
41
50
|
deleteJob(jobId: JobId): void;
|
|
42
51
|
getJob(id: JobId): Job | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sqlite.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/persistence/sqlite.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,EAAE,KAAK,GAAG,EAAE,KAAK,KAAK,EAAS,MAAM,wBAAwB,CAAC;AACrE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAqBvD,2BAA2B;AAC3B,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IACxC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uCAAuC;IACvC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,sDAAsD;IACtD,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;GAEG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAW;IAC9B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAsD;IAGjF,OAAO,CAAC,WAAW,CAAa;IAChC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,gBAAgB,CAA+C;IAGvE,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAsD;gBAE3E,MAAM,EAAE,YAAY;IAgBhC,iCAAiC;IACjC,gBAAgB,IAAI,IAAI;IASxB,OAAO,CAAC,OAAO;IAgBf,0DAA0D;IAC1D,SAAS,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI;IASzB,6CAA6C;IAC7C,kBAAkB,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI;IA6BlC,UAAU,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAIjD,aAAa,CAAC,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI;IAItD,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;
|
|
1
|
+
{"version":3,"file":"sqlite.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/persistence/sqlite.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,EAAE,KAAK,GAAG,EAAE,KAAK,KAAK,EAAS,MAAM,wBAAwB,CAAC;AACrE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAqBvD,2BAA2B;AAC3B,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IACxC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uCAAuC;IACvC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,sDAAsD;IACtD,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;GAEG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAW;IAC9B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAsD;IAGjF,OAAO,CAAC,WAAW,CAAa;IAChC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,gBAAgB,CAA+C;IAGvE,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAsD;gBAE3E,MAAM,EAAE,YAAY;IAgBhC,iCAAiC;IACjC,gBAAgB,IAAI,IAAI;IASxB,OAAO,CAAC,OAAO;IAgBf,0DAA0D;IAC1D,SAAS,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI;IASzB,6CAA6C;IAC7C,kBAAkB,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI;IA6BlC,UAAU,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAIjD,aAAa,CAAC,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI;IAItD,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAKhD,wCAAwC;IACxC,YAAY,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI;IAMnC,iCAAiC;IACjC,cAAc,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAIlC,wCAAwC;IACxC,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAIlC,2BAA2B;IAC3B,OAAO,IAAI,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC;IAsClC,cAAc,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI;IAM9B,SAAS,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAI7B,MAAM,CAAC,EAAE,EAAE,KAAK,GAAG,GAAG,GAAG,IAAI;IAK7B,WAAW,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,GAAG,IAAI;IAIhD,SAAS,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO;IAOhC,4CAA4C;IAC5C,eAAe,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI;IAUlC,iFAAiF;IACjF,OAAO,CAAC,uBAAuB;IAgB/B,+DAA+D;IAC/D,OAAO,CAAC,kBAAkB;IAmB1B,0DAA0D;IAC1D,OAAO,CAAC,eAAe;IAsCvB,eAAe,IAAI,GAAG,EAAE;IAOxB,cAAc,IAAI,GAAG,EAAE;IASvB,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI;IAgB7B,YAAY,IAAI,OAAO,EAAE;IAezB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAM9B,OAAO,CAAC,QAAQ;IA4ChB,KAAK,IAAI,IAAI;IAab,OAAO,IAAI,MAAM;CAIlB"}
|
|
@@ -91,9 +91,51 @@ export class SqliteStorage {
|
|
|
91
91
|
this.statements.get('completeJob').run('completed', completedAt, jobId);
|
|
92
92
|
}
|
|
93
93
|
markFailed(job, error) {
|
|
94
|
+
// Legacy method - use saveDlqEntry for full metadata
|
|
95
|
+
this.statements.get('insertDlq').run(job.id, job.queue, pack({ job, error }), Date.now());
|
|
96
|
+
}
|
|
97
|
+
/** Save DLQ entry with full metadata */
|
|
98
|
+
saveDlqEntry(entry) {
|
|
94
99
|
this.statements
|
|
95
100
|
.get('insertDlq')
|
|
96
|
-
.run(job.id, job.queue, pack(
|
|
101
|
+
.run(entry.job.id, entry.job.queue, pack(entry), entry.enteredAt);
|
|
102
|
+
}
|
|
103
|
+
/** Delete DLQ entry by job ID */
|
|
104
|
+
deleteDlqEntry(jobId) {
|
|
105
|
+
this.statements.get('deleteDlqEntry').run(jobId);
|
|
106
|
+
}
|
|
107
|
+
/** Clear all DLQ entries for a queue */
|
|
108
|
+
clearDlqQueue(queue) {
|
|
109
|
+
this.statements.get('clearDlqQueue').run(queue);
|
|
110
|
+
}
|
|
111
|
+
/** Load all DLQ entries */
|
|
112
|
+
loadDlq() {
|
|
113
|
+
const rows = this.statements.get('loadDlq').all();
|
|
114
|
+
const result = new Map();
|
|
115
|
+
for (const row of rows) {
|
|
116
|
+
const entry = unpack(row.entry, null, `loadDlq:${row.job_id}`);
|
|
117
|
+
if (!entry?.job)
|
|
118
|
+
continue;
|
|
119
|
+
// Reconstruct jobId type (MessagePack serializes it as string)
|
|
120
|
+
const reconstructedEntry = {
|
|
121
|
+
...entry,
|
|
122
|
+
job: {
|
|
123
|
+
...entry.job,
|
|
124
|
+
id: jobId(String(entry.job.id)),
|
|
125
|
+
dependsOn: entry.job.dependsOn.map((id) => jobId(String(id))),
|
|
126
|
+
parentId: entry.job.parentId ? jobId(String(entry.job.parentId)) : null,
|
|
127
|
+
childrenIds: entry.job.childrenIds.map((id) => jobId(String(id))),
|
|
128
|
+
},
|
|
129
|
+
};
|
|
130
|
+
let queueEntries = result.get(row.queue);
|
|
131
|
+
if (!queueEntries) {
|
|
132
|
+
queueEntries = [];
|
|
133
|
+
result.set(row.queue, queueEntries);
|
|
134
|
+
}
|
|
135
|
+
queueEntries.push(reconstructedEntry);
|
|
136
|
+
}
|
|
137
|
+
storageLog.info('Loaded DLQ entries', { count: rows.length });
|
|
138
|
+
return result;
|
|
97
139
|
}
|
|
98
140
|
updateForRetry(job) {
|
|
99
141
|
this.db
|