bunqueue 2.8.12 → 2.8.13
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.
|
@@ -6,7 +6,7 @@ import { createPublicJob } from '../types';
|
|
|
6
6
|
import { getSharedManager } from '../manager';
|
|
7
7
|
import { UnrecoverableError } from '../errors';
|
|
8
8
|
import { DelayedError } from '../errors';
|
|
9
|
-
import { createProgressHandler, createLogHandler, createGetStateHandler, createGetChildrenValuesHandler, createGetFailedChildrenValuesHandler, createGetIgnoredChildrenFailuresHandler, createRemoveChildDependencyHandler, createRemoveUnprocessedChildrenHandler, createMoveToFailedHandler, createMoveToCompletedHandler, createRemoveHandler, createRetryHandler, createUpdateDataHandler, createPromoteHandler, createChangeDelayHandler, createChangePriorityHandler, createExtendLockHandler, createClearLogsHandler, createMoveToWaitHandler, createMoveToDelayedHandler, createMoveToWaitingChildrenHandler, createWaitUntilFinishedHandler, createDiscardHandler, createGetDependenciesHandler, createGetDependenciesCountHandler, createRemoveDeduplicationKeyHandler, } from './processorHandlers';
|
|
9
|
+
import { createProgressHandler, createLogHandler, createGetStateHandler, createGetChildrenValuesHandler, createGetFailedChildrenValuesHandler, createGetIgnoredChildrenFailuresHandler, createRemoveChildDependencyHandler, createRemoveUnprocessedChildrenHandler, createMoveToFailedHandler, createMoveToCompletedHandler, createRemoveHandler, createRetryHandler, createUpdateDataHandler, createPromoteHandler, createChangeDelayHandler, createChangePriorityHandler, createExtendLockHandler, createClearLogsHandler, createMoveToWaitHandler, createMoveToDelayedHandler, createMoveToWaitingChildrenHandler, createWaitUntilFinishedHandler, createDiscardHandler, createGetDependenciesHandler, createGetDependenciesCountHandler, createRemoveDeduplicationKeyHandler, computeStackLines, } from './processorHandlers';
|
|
10
10
|
/**
|
|
11
11
|
* Process a single job
|
|
12
12
|
*/
|
|
@@ -63,7 +63,7 @@ export async function processJob(internalJob, config) {
|
|
|
63
63
|
try {
|
|
64
64
|
const result = await processor(job);
|
|
65
65
|
// Issue #82: If moveToFailed/moveToCompleted was called, skip auto-ACK
|
|
66
|
-
if (handleManualMove(manualMove, job, config))
|
|
66
|
+
if (handleManualMove(manualMove, job, config, internalJob))
|
|
67
67
|
return;
|
|
68
68
|
// Normal path: auto-ACK
|
|
69
69
|
try {
|
|
@@ -94,16 +94,23 @@ export async function processJob(internalJob, config) {
|
|
|
94
94
|
}
|
|
95
95
|
catch (error) {
|
|
96
96
|
// Issue #82: If moveToFailed was already called, skip normal failure handling
|
|
97
|
-
if (handleManualMove(manualMove, job, config))
|
|
97
|
+
if (handleManualMove(manualMove, job, config, internalJob))
|
|
98
98
|
return;
|
|
99
99
|
await handleJobFailure(internalJob, error, config, { job, jobIdStr, token });
|
|
100
100
|
}
|
|
101
101
|
}
|
|
102
102
|
/** Issue #82: Handle explicit moveToFailed/moveToCompleted called inside processor */
|
|
103
|
-
function handleManualMove(manualMove, job, config) {
|
|
103
|
+
function handleManualMove(manualMove, job, config, internalJob) {
|
|
104
104
|
if (manualMove.result?.type === 'failed') {
|
|
105
105
|
const err = manualMove.result.error ?? new Error('Job manually moved to failed');
|
|
106
106
|
job.failedReason = err.message;
|
|
107
|
+
// Bug #74 follow-up: populate stacktrace on the local `failed` event for the
|
|
108
|
+
// explicit moveToFailed() path too, mirroring handleJobFailure. The stack is
|
|
109
|
+
// persisted server-side by createMoveToFailedHandler's FAIL/manager.fail call.
|
|
110
|
+
if (err.stack) {
|
|
111
|
+
const { stackLines } = computeStackLines(err);
|
|
112
|
+
job.stacktrace = stackLines.slice(0, internalJob.stackTraceLimit);
|
|
113
|
+
}
|
|
107
114
|
config.onOutcome?.(false);
|
|
108
115
|
config.emitter.emit('failed', job, err);
|
|
109
116
|
return true;
|
|
@@ -160,13 +167,7 @@ async function handleJobFailure(internalJob, error, config, context) {
|
|
|
160
167
|
// Bug #74: stack lines computed BEFORE the send so the server can persist
|
|
161
168
|
// them. The wire copy is capped at 50 lines as a bandwidth guard; the
|
|
162
169
|
// authoritative cap (job.stackTraceLimit) is applied server-side in failJob.
|
|
163
|
-
const stackLines = err
|
|
164
|
-
? err.stack
|
|
165
|
-
.split('\n')
|
|
166
|
-
.map((l) => l.trim())
|
|
167
|
-
.filter(Boolean)
|
|
168
|
-
: [];
|
|
169
|
-
const wireStack = stackLines.length > 0 ? stackLines.slice(0, 50) : undefined;
|
|
170
|
+
const { stackLines, wireStack } = computeStackLines(err);
|
|
170
171
|
try {
|
|
171
172
|
if (embedded) {
|
|
172
173
|
const manager = getSharedManager();
|
|
@@ -19,6 +19,17 @@ export declare function createGetFailedChildrenValuesHandler(embedded: boolean,
|
|
|
19
19
|
export declare function createGetIgnoredChildrenFailuresHandler(embedded: boolean, tcp: TcpConnection | null): (id: string) => Promise<Record<string, string>>;
|
|
20
20
|
export declare function createRemoveChildDependencyHandler(embedded: boolean, tcp: TcpConnection | null): (id: string) => Promise<boolean>;
|
|
21
21
|
export declare function createRemoveUnprocessedChildrenHandler(embedded: boolean, tcp: TcpConnection | null): (id: string) => Promise<void>;
|
|
22
|
+
/**
|
|
23
|
+
* Bug #74: split an Error's stack into trimmed, non-empty lines.
|
|
24
|
+
* `wireStack` is the bandwidth-capped copy sent to the server (50 lines); the
|
|
25
|
+
* authoritative cap (job.stackTraceLimit) is applied server-side in failJob.
|
|
26
|
+
* Shared by the natural-throw path (handleJobFailure) and the explicit
|
|
27
|
+
* moveToFailed() path so both persist the stack identically.
|
|
28
|
+
*/
|
|
29
|
+
export declare function computeStackLines(err: Error): {
|
|
30
|
+
stackLines: string[];
|
|
31
|
+
wireStack: string[] | undefined;
|
|
32
|
+
};
|
|
22
33
|
/** Issue #82: Create moveToFailed handler for use inside processor */
|
|
23
34
|
export declare function createMoveToFailedHandler(embedded: boolean, tcp: TcpConnection | null, internalJob: InternalJob, token: string | null | undefined, onCalled: (error: Error) => void): (id: string, error: Error, _lockToken?: string) => Promise<void>;
|
|
24
35
|
/** Issue #82: Create moveToCompleted handler for use inside processor */
|
|
@@ -102,18 +102,40 @@ export function createRemoveUnprocessedChildrenHandler(embedded, tcp) {
|
|
|
102
102
|
await tcp.send({ cmd: 'RemoveUnprocessedChildren', id });
|
|
103
103
|
};
|
|
104
104
|
}
|
|
105
|
+
/**
|
|
106
|
+
* Bug #74: split an Error's stack into trimmed, non-empty lines.
|
|
107
|
+
* `wireStack` is the bandwidth-capped copy sent to the server (50 lines); the
|
|
108
|
+
* authoritative cap (job.stackTraceLimit) is applied server-side in failJob.
|
|
109
|
+
* Shared by the natural-throw path (handleJobFailure) and the explicit
|
|
110
|
+
* moveToFailed() path so both persist the stack identically.
|
|
111
|
+
*/
|
|
112
|
+
export function computeStackLines(err) {
|
|
113
|
+
const stackLines = err.stack
|
|
114
|
+
? err.stack
|
|
115
|
+
.split('\n')
|
|
116
|
+
.map((l) => l.trim())
|
|
117
|
+
.filter(Boolean)
|
|
118
|
+
: [];
|
|
119
|
+
const wireStack = stackLines.length > 0 ? stackLines.slice(0, 50) : undefined;
|
|
120
|
+
return { stackLines, wireStack };
|
|
121
|
+
}
|
|
105
122
|
/** Issue #82: Create moveToFailed handler for use inside processor */
|
|
106
123
|
export function createMoveToFailedHandler(embedded, tcp, internalJob, token, onCalled) {
|
|
107
124
|
return async (_id, error, _lockToken) => {
|
|
125
|
+
// Bug #74 follow-up: carry the stack on explicit moveToFailed() too. The
|
|
126
|
+
// natural-throw path already does; @arthurvanl's repro showed the manual
|
|
127
|
+
// path lost it. Compute before the send so the server can persist it.
|
|
128
|
+
const { wireStack } = computeStackLines(error);
|
|
108
129
|
if (embedded) {
|
|
109
130
|
const manager = getSharedManager();
|
|
110
|
-
await manager.fail(internalJob.id, error.message, token ?? undefined);
|
|
131
|
+
await manager.fail(internalJob.id, error.message, token ?? undefined, undefined, wireStack);
|
|
111
132
|
}
|
|
112
133
|
else if (tcp) {
|
|
113
134
|
await tcp.send({
|
|
114
135
|
cmd: 'FAIL',
|
|
115
136
|
id: internalJob.id,
|
|
116
137
|
error: error.message,
|
|
138
|
+
...(wireStack ? { stack: wireStack } : {}),
|
|
117
139
|
...(token ? { token } : {}),
|
|
118
140
|
});
|
|
119
141
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bunqueue",
|
|
3
|
-
"version": "2.8.
|
|
3
|
+
"version": "2.8.13",
|
|
4
4
|
"description": "High-performance job queue for Bun & AI agents. SQLite persistence, cron scheduling, priorities, retries, DLQ, webhooks, native MCP server. Zero external dependencies.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/main.js",
|