bunqueue 2.7.18 → 2.7.20
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/backgroundTasks.d.ts.map +1 -1
- package/dist/application/backgroundTasks.js +41 -0
- package/dist/application/backgroundTasks.js.map +1 -1
- package/dist/application/operations/queueControl.d.ts.map +1 -1
- package/dist/application/operations/queueControl.js +5 -1
- package/dist/application/operations/queueControl.js.map +1 -1
- package/dist/application/queueManager.d.ts +8 -1
- package/dist/application/queueManager.d.ts.map +1 -1
- package/dist/application/queueManager.js +37 -23
- package/dist/application/queueManager.js.map +1 -1
- package/dist/client/queue/operations/add.d.ts.map +1 -1
- package/dist/client/queue/operations/add.js +7 -2
- package/dist/client/queue/operations/add.js.map +1 -1
- package/dist/client/tcp/client.d.ts.map +1 -1
- package/dist/client/tcp/client.js +11 -8
- package/dist/client/tcp/client.js.map +1 -1
- package/dist/client/worker/ackBatcher.d.ts.map +1 -1
- package/dist/client/worker/ackBatcher.js +18 -8
- package/dist/client/worker/ackBatcher.js.map +1 -1
- package/dist/client/workflow/compensator.d.ts.map +1 -1
- package/dist/client/workflow/compensator.js +10 -2
- package/dist/client/workflow/compensator.js.map +1 -1
- package/dist/client/workflow/executor.d.ts.map +1 -1
- package/dist/client/workflow/executor.js +5 -1
- package/dist/client/workflow/executor.js.map +1 -1
- package/dist/client/workflow/loops.d.ts.map +1 -1
- package/dist/client/workflow/loops.js +7 -0
- package/dist/client/workflow/loops.js.map +1 -1
- package/dist/client/workflow/types.d.ts +4 -0
- package/dist/client/workflow/types.d.ts.map +1 -1
- package/dist/domain/queue/dlqShard.d.ts.map +1 -1
- package/dist/domain/queue/dlqShard.js +6 -0
- package/dist/domain/queue/dlqShard.js.map +1 -1
- package/dist/infrastructure/backup/s3BackupOperations.d.ts.map +1 -1
- package/dist/infrastructure/backup/s3BackupOperations.js +44 -6
- package/dist/infrastructure/backup/s3BackupOperations.js.map +1 -1
- package/dist/infrastructure/cloud/cloudAgent.d.ts +1 -1
- package/dist/infrastructure/cloud/cloudAgent.d.ts.map +1 -1
- package/dist/infrastructure/cloud/cloudAgent.js +9 -11
- package/dist/infrastructure/cloud/cloudAgent.js.map +1 -1
- package/dist/infrastructure/cloud/redact.d.ts +11 -0
- package/dist/infrastructure/cloud/redact.d.ts.map +1 -0
- package/dist/infrastructure/cloud/redact.js +22 -0
- package/dist/infrastructure/cloud/redact.js.map +1 -0
- package/dist/infrastructure/cloud/snapshotCollector.d.ts +4 -0
- package/dist/infrastructure/cloud/snapshotCollector.d.ts.map +1 -1
- package/dist/infrastructure/cloud/snapshotCollector.js +32 -17
- package/dist/infrastructure/cloud/snapshotCollector.js.map +1 -1
- package/dist/infrastructure/cloud/snapshotHelpers.d.ts +9 -2
- package/dist/infrastructure/cloud/snapshotHelpers.d.ts.map +1 -1
- package/dist/infrastructure/cloud/snapshotHelpers.js +10 -8
- package/dist/infrastructure/cloud/snapshotHelpers.js.map +1 -1
- package/dist/infrastructure/persistence/sqlite.d.ts +1 -1
- package/dist/infrastructure/persistence/sqlite.d.ts.map +1 -1
- package/dist/infrastructure/persistence/sqlite.js +18 -0
- package/dist/infrastructure/persistence/sqlite.js.map +1 -1
- package/dist/infrastructure/persistence/sqliteSerializer.d.ts +16 -0
- package/dist/infrastructure/persistence/sqliteSerializer.d.ts.map +1 -1
- package/dist/infrastructure/persistence/sqliteSerializer.js +73 -8
- package/dist/infrastructure/persistence/sqliteSerializer.js.map +1 -1
- package/dist/infrastructure/scheduler/cronScheduler.d.ts.map +1 -1
- package/dist/infrastructure/scheduler/cronScheduler.js +11 -1
- package/dist/infrastructure/scheduler/cronScheduler.js.map +1 -1
- package/dist/infrastructure/server/protocol.d.ts +4 -0
- package/dist/infrastructure/server/protocol.d.ts.map +1 -1
- package/dist/infrastructure/server/protocol.js +17 -2
- package/dist/infrastructure/server/protocol.js.map +1 -1
- package/dist/infrastructure/server/socketWriteQueue.d.ts +67 -0
- package/dist/infrastructure/server/socketWriteQueue.d.ts.map +1 -0
- package/dist/infrastructure/server/socketWriteQueue.js +127 -0
- package/dist/infrastructure/server/socketWriteQueue.js.map +1 -0
- package/dist/infrastructure/server/tcp.d.ts +17 -0
- package/dist/infrastructure/server/tcp.d.ts.map +1 -1
- package/dist/infrastructure/server/tcp.js +104 -10
- package/dist/infrastructure/server/tcp.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-socket write queue
|
|
3
|
+
* =================================================================
|
|
4
|
+
* Bun's `socket.write()` may write FEWER bytes than provided when the kernel
|
|
5
|
+
* send buffer is full (backpressure). The unwritten tail is NOT retained by
|
|
6
|
+
* Bun — the caller is responsible for buffering it and resending once the
|
|
7
|
+
* socket fires `drain`. Ignoring the short count silently drops response
|
|
8
|
+
* bytes, corrupting the length-prefixed frame protocol.
|
|
9
|
+
*
|
|
10
|
+
* This helper buffers any unwritten tail per-socket and preserves ordering:
|
|
11
|
+
* while a pending tail exists, all subsequent writes are appended to the queue
|
|
12
|
+
* (never written ahead of older bytes), and the queue is flushed in order from
|
|
13
|
+
* the `drain` handler.
|
|
14
|
+
*/
|
|
15
|
+
/** Per-socket pending write state. Stored on `socket.data`. */
|
|
16
|
+
export class SocketWriteQueue {
|
|
17
|
+
/** Buffered chunks waiting to be (re)written, in order. */
|
|
18
|
+
pending = [];
|
|
19
|
+
/** Byte offset into pending[0] already written by a short write. */
|
|
20
|
+
offset = 0;
|
|
21
|
+
/** Total queued bytes (for bounds / observability). */
|
|
22
|
+
queuedBytes = 0;
|
|
23
|
+
/** Max queued bytes before the queue reports over-budget (0 = unbounded). */
|
|
24
|
+
maxBytes;
|
|
25
|
+
/**
|
|
26
|
+
* @param maxBytes Soft cap on buffered bytes. When `bytesQueued` exceeds this,
|
|
27
|
+
* `isOverBudget` becomes true and the owner should drop the connection
|
|
28
|
+
* (bounds write-side memory for a client that stopped reading). 0 disables.
|
|
29
|
+
*/
|
|
30
|
+
constructor(maxBytes = 0) {
|
|
31
|
+
this.maxBytes = maxBytes > 0 ? maxBytes : 0;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* True once the buffered byte count exceeds the configured cap. The owner is
|
|
35
|
+
* expected to terminate the connection and `clear()` the queue.
|
|
36
|
+
*/
|
|
37
|
+
get isOverBudget() {
|
|
38
|
+
return this.maxBytes > 0 && this.queuedBytes > this.maxBytes;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Enqueue `data` for delivery on `socket`, preserving order.
|
|
42
|
+
* Returns false if the socket appears closed (write threw / returned < 0).
|
|
43
|
+
*/
|
|
44
|
+
write(socket, data) {
|
|
45
|
+
if (data.length === 0)
|
|
46
|
+
return true;
|
|
47
|
+
// If a tail is already pending, do NOT write ahead of it — append and wait
|
|
48
|
+
// for drain to flush in order.
|
|
49
|
+
if (this.pending.length > 0) {
|
|
50
|
+
this.pending.push(data);
|
|
51
|
+
this.queuedBytes += data.length;
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
let written;
|
|
55
|
+
try {
|
|
56
|
+
written = socket.write(data);
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
if (written < 0) {
|
|
62
|
+
// Socket closed.
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
if (written < data.length) {
|
|
66
|
+
// Short write: buffer the unwritten tail; flush on drain.
|
|
67
|
+
const tail = data.subarray(written);
|
|
68
|
+
this.pending.push(tail);
|
|
69
|
+
this.queuedBytes += tail.length;
|
|
70
|
+
}
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Flush as much of the pending queue as the socket accepts.
|
|
75
|
+
* Call from the socket's `drain` handler. Stops at the first short write,
|
|
76
|
+
* leaving the remainder queued for the next drain.
|
|
77
|
+
*/
|
|
78
|
+
flush(socket) {
|
|
79
|
+
while (this.pending.length > 0) {
|
|
80
|
+
const chunk = this.pending[0];
|
|
81
|
+
const view = this.offset > 0 ? chunk.subarray(this.offset) : chunk;
|
|
82
|
+
let written;
|
|
83
|
+
try {
|
|
84
|
+
written = socket.write(view);
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
if (written <= 0) {
|
|
90
|
+
// Socket not ready / closed; wait for the next drain.
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
if (written < view.length) {
|
|
94
|
+
// Still backpressured: advance offset within the current chunk.
|
|
95
|
+
this.offset += written;
|
|
96
|
+
this.queuedBytes -= written;
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
// Whole chunk flushed.
|
|
100
|
+
this.queuedBytes -= view.length;
|
|
101
|
+
this.pending.shift();
|
|
102
|
+
this.offset = 0;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/** Number of bytes still buffered awaiting drain. */
|
|
106
|
+
get bytesQueued() {
|
|
107
|
+
return this.queuedBytes;
|
|
108
|
+
}
|
|
109
|
+
/** Whether there is unwritten data awaiting drain. */
|
|
110
|
+
get hasPending() {
|
|
111
|
+
return this.pending.length > 0;
|
|
112
|
+
}
|
|
113
|
+
/** Drop all buffered data (e.g. on close). */
|
|
114
|
+
clear() {
|
|
115
|
+
this.pending = [];
|
|
116
|
+
this.offset = 0;
|
|
117
|
+
this.queuedBytes = 0;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Convenience: write through a socket whose `data` carries a `writeQueue`.
|
|
122
|
+
* Keeps call sites in tcp.ts terse and consistent.
|
|
123
|
+
*/
|
|
124
|
+
export function queuedWrite(socket, data) {
|
|
125
|
+
socket.data.writeQueue.write(socket, data);
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=socketWriteQueue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"socketWriteQueue.js","sourceRoot":"","sources":["../../../src/infrastructure/server/socketWriteQueue.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,6 +8,7 @@ import type { QueueManager } from '../../application/queueManager';
|
|
|
8
8
|
import { type HandlerContext } from './handler';
|
|
9
9
|
import { FrameParser, type ConnectionState } from './protocol';
|
|
10
10
|
import { Semaphore } from '../../shared/semaphore';
|
|
11
|
+
import { SocketWriteQueue } from './socketWriteQueue';
|
|
11
12
|
/** TCP Server configuration */
|
|
12
13
|
export interface TcpServerConfig {
|
|
13
14
|
/** TCP port */
|
|
@@ -16,6 +17,18 @@ export interface TcpServerConfig {
|
|
|
16
17
|
hostname?: string;
|
|
17
18
|
/** Auth tokens for authentication */
|
|
18
19
|
authTokens?: string[];
|
|
20
|
+
/**
|
|
21
|
+
* Slowloris stall timeout (ms): close a connection that started a frame but
|
|
22
|
+
* made no progress completing it within this window. 0 disables. Defaults to
|
|
23
|
+
* TCP_IDLE_TIMEOUT_MS env (60s). Mainly for tests.
|
|
24
|
+
*/
|
|
25
|
+
idleTimeoutMs?: number;
|
|
26
|
+
/**
|
|
27
|
+
* Max outbound write-queue bytes before dropping a connection (write-side
|
|
28
|
+
* memory bound). 0 disables. Defaults to TCP_MAX_WRITE_QUEUE_BYTES env (64MB).
|
|
29
|
+
* Mainly for tests.
|
|
30
|
+
*/
|
|
31
|
+
maxWriteQueueBytes?: number;
|
|
19
32
|
}
|
|
20
33
|
/** Per-connection data */
|
|
21
34
|
interface ConnectionData {
|
|
@@ -24,6 +37,10 @@ interface ConnectionData {
|
|
|
24
37
|
ctx: HandlerContext;
|
|
25
38
|
/** Semaphore for limiting concurrent command processing (pipelining) */
|
|
26
39
|
semaphore: Semaphore;
|
|
40
|
+
/** Backpressure-aware write queue: buffers unwritten tails, flushes on drain */
|
|
41
|
+
writeQueue: SocketWriteQueue;
|
|
42
|
+
/** Active partial-frame stall timer (slowloris mitigation); null when idle. */
|
|
43
|
+
stallTimer: ReturnType<typeof setTimeout> | null;
|
|
27
44
|
}
|
|
28
45
|
/**
|
|
29
46
|
* Create and start TCP server
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tcp.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/server/tcp.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,KAAK,CAAC;AACrD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAGnE,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC;AAC/D,OAAO,EACL,WAAW,EAGX,KAAK,eAAe,EACrB,MAAM,YAAY,CAAC;AAKpB,OAAO,EAAE,SAAS,EAAiB,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"tcp.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/server/tcp.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,KAAK,CAAC;AACrD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAGnE,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC;AAC/D,OAAO,EACL,WAAW,EAGX,KAAK,eAAe,EACrB,MAAM,YAAY,CAAC;AAKpB,OAAO,EAAE,SAAS,EAAiB,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AA0DtD,+BAA+B;AAC/B,MAAM,WAAW,eAAe;IAC9B,eAAe;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,uBAAuB;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qCAAqC;IACrC,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,0BAA0B;AAC1B,UAAU,cAAc;IACtB,KAAK,EAAE,eAAe,CAAC;IACvB,WAAW,EAAE,WAAW,CAAC;IACzB,GAAG,EAAE,cAAc,CAAC;IACpB,wEAAwE;IACxE,SAAS,EAAE,SAAS,CAAC;IACrB,gFAAgF;IAChF,UAAU,EAAE,gBAAgB,CAAC;IAC7B,+EAA+E;IAC/E,UAAU,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,GAAG,IAAI,CAAC;CAClD;AAYD;;GAEG;AACH,wBAAgB,eAAe,CAAC,YAAY,EAAE,YAAY,EAAE,MAAM,EAAE,eAAe;;;IAwM/E,2BAA2B;0BACL,MAAM;IAI5B,mCAAmC;uBAChB,OAAO,GAAG,IAAI;IAejC,sBAAsB;YACd,IAAI;EASf;AAED,MAAM,MAAM,SAAS,GAAG,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC"}
|
|
@@ -10,8 +10,29 @@ import { tcpLog } from '../../shared/logger';
|
|
|
10
10
|
import { getRateLimiter } from './rateLimiter';
|
|
11
11
|
import { pack, unpack } from 'msgpackr';
|
|
12
12
|
import { Semaphore, withSemaphore } from '../../shared/semaphore';
|
|
13
|
+
import { SocketWriteQueue } from './socketWriteQueue';
|
|
13
14
|
/** Max concurrent commands per connection for pipelining */
|
|
14
15
|
const MAX_CONCURRENT_PER_CONNECTION = 50;
|
|
16
|
+
/**
|
|
17
|
+
* Idle/read stall timeout (ms) for the slowloris mitigation. A connection that
|
|
18
|
+
* has STARTED a frame (partial bytes buffered) but makes no further progress
|
|
19
|
+
* toward completing it within this window is closed. Healthy connections that
|
|
20
|
+
* are simply idle (no partial frame buffered) are never affected, so long-lived
|
|
21
|
+
* idle-but-healthy clients are not disturbed. 0 disables the timeout.
|
|
22
|
+
*
|
|
23
|
+
* Implemented with a manual per-connection timer (Bun.listen has no
|
|
24
|
+
* `idleTimeout` socket option as of Bun 1.3.x, and `socket.timeout()` resets on
|
|
25
|
+
* every byte — so a slowloris that trickles one byte per window would defeat
|
|
26
|
+
* it). The manual timer is armed only while a partial frame is in progress.
|
|
27
|
+
*/
|
|
28
|
+
const TCP_IDLE_TIMEOUT_MS = Math.max(0, parseInt(Bun.env.TCP_IDLE_TIMEOUT_MS ?? '60000', 10) || 0);
|
|
29
|
+
/**
|
|
30
|
+
* Maximum bytes that may be buffered in a connection's outbound write queue
|
|
31
|
+
* before the connection is dropped. A client that stops reading while the
|
|
32
|
+
* server keeps producing responses would otherwise grow the pending queue
|
|
33
|
+
* without bound (write-side memory DoS). Generous default (64MB). 0 disables.
|
|
34
|
+
*/
|
|
35
|
+
const MAX_WRITE_QUEUE_BYTES = Math.max(0, parseInt(Bun.env.TCP_MAX_WRITE_QUEUE_BYTES ?? String(64 * 1024 * 1024), 10) || 0);
|
|
15
36
|
/**
|
|
16
37
|
* Release client jobs with retry logic and exponential backoff.
|
|
17
38
|
* Ensures jobs are not left in an inconsistent state if release fails.
|
|
@@ -48,6 +69,39 @@ function errorResponse(message, reqId) {
|
|
|
48
69
|
export function createTcpServer(queueManager, config) {
|
|
49
70
|
const authTokens = new Set(config.authTokens ?? []);
|
|
50
71
|
const connections = new Map();
|
|
72
|
+
const idleTimeoutMs = config.idleTimeoutMs ?? TCP_IDLE_TIMEOUT_MS;
|
|
73
|
+
const maxWriteQueueBytes = config.maxWriteQueueBytes ?? MAX_WRITE_QUEUE_BYTES;
|
|
74
|
+
/** Cancel any pending stall timer for a connection. */
|
|
75
|
+
function clearStallTimer(socket) {
|
|
76
|
+
if (socket.data.stallTimer !== null) {
|
|
77
|
+
clearTimeout(socket.data.stallTimer);
|
|
78
|
+
socket.data.stallTimer = null;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* (Re)arm the slowloris stall timer based on parser state. The timer runs
|
|
83
|
+
* ONLY while a partial frame is buffered (a frame was started but not yet
|
|
84
|
+
* completed). It is reset on every data event that still leaves a partial
|
|
85
|
+
* frame, and cleared once the buffer drains to empty (frame completed). If it
|
|
86
|
+
* fires, the peer started a frame and then stalled -> terminate.
|
|
87
|
+
*/
|
|
88
|
+
function updateStallTimer(socket) {
|
|
89
|
+
if (idleTimeoutMs <= 0)
|
|
90
|
+
return;
|
|
91
|
+
clearStallTimer(socket);
|
|
92
|
+
if (!socket.data.frameParser.hasPartialFrame)
|
|
93
|
+
return;
|
|
94
|
+
socket.data.stallTimer = setTimeout(() => {
|
|
95
|
+
socket.data.stallTimer = null;
|
|
96
|
+
tcpLog.warn('Closing stalled connection (incomplete frame)', {
|
|
97
|
+
clientId: socket.data.state.clientId,
|
|
98
|
+
bufferedBytes: socket.data.frameParser.bufferedBytes,
|
|
99
|
+
idleTimeoutMs,
|
|
100
|
+
});
|
|
101
|
+
socket.data.writeQueue.clear();
|
|
102
|
+
socket.terminate();
|
|
103
|
+
}, idleTimeoutMs);
|
|
104
|
+
}
|
|
51
105
|
const socketHandlers = {
|
|
52
106
|
open(socket) {
|
|
53
107
|
const clientId = uuid();
|
|
@@ -63,17 +117,19 @@ export function createTcpServer(queueManager, config) {
|
|
|
63
117
|
frameParser: new FrameParser(),
|
|
64
118
|
ctx,
|
|
65
119
|
semaphore: new Semaphore(MAX_CONCURRENT_PER_CONNECTION),
|
|
120
|
+
writeQueue: new SocketWriteQueue(maxWriteQueueBytes),
|
|
121
|
+
stallTimer: null,
|
|
66
122
|
};
|
|
67
123
|
connections.set(clientId, socket);
|
|
68
124
|
queueManager.emitDashboardEvent('client:connected', { clientId, transport: 'tcp' });
|
|
69
125
|
},
|
|
70
126
|
async data(socket, data) {
|
|
71
|
-
const { frameParser, ctx, state, semaphore } = socket.data;
|
|
127
|
+
const { frameParser, ctx, state, semaphore, writeQueue } = socket.data;
|
|
72
128
|
const rateLimiter = getRateLimiter();
|
|
73
129
|
// Check rate limit
|
|
74
130
|
if (!rateLimiter.isAllowed(state.clientId)) {
|
|
75
131
|
ctx.queueManager.emitDashboardEvent('ratelimit:hit', { clientId: state.clientId });
|
|
76
|
-
|
|
132
|
+
writeQueue.write(socket, errorResponse('Rate limit exceeded'));
|
|
77
133
|
return;
|
|
78
134
|
}
|
|
79
135
|
let frames;
|
|
@@ -82,12 +138,33 @@ export function createTcpServer(queueManager, config) {
|
|
|
82
138
|
}
|
|
83
139
|
catch (err) {
|
|
84
140
|
if (err instanceof FrameSizeError) {
|
|
85
|
-
socket
|
|
141
|
+
clearStallTimer(socket);
|
|
142
|
+
writeQueue.write(socket, errorResponse(`Frame too large: ${err.requestedSize} bytes exceeds maximum ${err.maxSize}`));
|
|
86
143
|
socket.end();
|
|
87
144
|
return;
|
|
88
145
|
}
|
|
89
146
|
throw err;
|
|
90
147
|
}
|
|
148
|
+
// Slowloris mitigation: (re)arm the stall timer based on whether a partial
|
|
149
|
+
// frame is now buffered. Progress (a completed frame draining the buffer)
|
|
150
|
+
// disarms it; a started-but-unfinished frame arms it. This bounds memory
|
|
151
|
+
// held by a peer that declares a large (legal) frame then never finishes.
|
|
152
|
+
updateStallTimer(socket);
|
|
153
|
+
// Drop a connection whose outbound queue grew unbounded (client stopped
|
|
154
|
+
// reading while we keep producing responses) — bounds write-side memory.
|
|
155
|
+
const dropForWriteOverflow = () => {
|
|
156
|
+
if (writeQueue.isOverBudget) {
|
|
157
|
+
tcpLog.warn('Closing connection: write queue exceeded budget', {
|
|
158
|
+
clientId: state.clientId,
|
|
159
|
+
queuedBytes: writeQueue.bytesQueued,
|
|
160
|
+
});
|
|
161
|
+
clearStallTimer(socket);
|
|
162
|
+
writeQueue.clear();
|
|
163
|
+
socket.terminate();
|
|
164
|
+
return true;
|
|
165
|
+
}
|
|
166
|
+
return false;
|
|
167
|
+
};
|
|
91
168
|
// Process frames in parallel for pipelining support
|
|
92
169
|
// Each command is processed with semaphore-controlled concurrency
|
|
93
170
|
const processFrame = async (frame) => {
|
|
@@ -96,23 +173,25 @@ export function createTcpServer(queueManager, config) {
|
|
|
96
173
|
cmd = unpack(frame);
|
|
97
174
|
}
|
|
98
175
|
catch {
|
|
99
|
-
|
|
176
|
+
writeQueue.write(socket, errorResponse('Invalid command format'));
|
|
100
177
|
return;
|
|
101
178
|
}
|
|
102
179
|
if (!cmd?.cmd) {
|
|
103
|
-
|
|
180
|
+
writeQueue.write(socket, errorResponse('Invalid command'));
|
|
104
181
|
return;
|
|
105
182
|
}
|
|
106
183
|
// Process with concurrency limit
|
|
107
184
|
await withSemaphore(semaphore, async () => {
|
|
108
185
|
try {
|
|
109
186
|
const response = await handleCommand(cmd, ctx);
|
|
110
|
-
|
|
187
|
+
writeQueue.write(socket, serializeResponse(response));
|
|
188
|
+
dropForWriteOverflow();
|
|
111
189
|
}
|
|
112
190
|
catch (err) {
|
|
113
191
|
const raw = err instanceof Error ? err.message : 'Unknown error';
|
|
114
192
|
const message = raw.includes('SQLITE') || raw.includes('database') ? 'Internal server error' : raw;
|
|
115
|
-
|
|
193
|
+
writeQueue.write(socket, errorResponse(message, cmd.reqId));
|
|
194
|
+
dropForWriteOverflow();
|
|
116
195
|
}
|
|
117
196
|
});
|
|
118
197
|
};
|
|
@@ -121,6 +200,10 @@ export function createTcpServer(queueManager, config) {
|
|
|
121
200
|
},
|
|
122
201
|
close(socket) {
|
|
123
202
|
const clientId = socket.data.state.clientId;
|
|
203
|
+
// Cancel the slowloris stall timer and drop any buffered-but-unwritten
|
|
204
|
+
// bytes; the socket is gone.
|
|
205
|
+
clearStallTimer(socket);
|
|
206
|
+
socket.data.writeQueue.clear();
|
|
124
207
|
connections.delete(clientId);
|
|
125
208
|
getRateLimiter().removeClient(clientId);
|
|
126
209
|
queueManager.unregisterWorkersByClientId(clientId);
|
|
@@ -147,8 +230,10 @@ export function createTcpServer(queueManager, config) {
|
|
|
147
230
|
error(_socket, error) {
|
|
148
231
|
tcpLog.error('Connection error', { error: error.message });
|
|
149
232
|
},
|
|
150
|
-
drain(
|
|
151
|
-
//
|
|
233
|
+
drain(socket) {
|
|
234
|
+
// Socket is ready for more writes after backpressure: flush any unwritten
|
|
235
|
+
// tail bytes buffered by short writes, preserving frame order.
|
|
236
|
+
socket.data.writeQueue.flush(socket);
|
|
152
237
|
},
|
|
153
238
|
};
|
|
154
239
|
// Create TCP server
|
|
@@ -168,13 +253,22 @@ export function createTcpServer(queueManager, config) {
|
|
|
168
253
|
broadcast(message) {
|
|
169
254
|
const frame = FrameParser.frame(pack(message));
|
|
170
255
|
for (const socket of connections.values()) {
|
|
171
|
-
|
|
256
|
+
// Each connection writes through its own backpressure-aware queue so a
|
|
257
|
+
// slow reader buffers (in order) instead of dropping frame tail bytes.
|
|
258
|
+
socket.data.writeQueue.write(socket, frame);
|
|
259
|
+
// Drop any reader that has fallen too far behind (write-side bound).
|
|
260
|
+
if (socket.data.writeQueue.isOverBudget) {
|
|
261
|
+
clearStallTimer(socket);
|
|
262
|
+
socket.data.writeQueue.clear();
|
|
263
|
+
socket.terminate();
|
|
264
|
+
}
|
|
172
265
|
}
|
|
173
266
|
},
|
|
174
267
|
/** Stop the server */
|
|
175
268
|
stop() {
|
|
176
269
|
server.stop();
|
|
177
270
|
for (const socket of connections.values()) {
|
|
271
|
+
clearStallTimer(socket);
|
|
178
272
|
socket.end();
|
|
179
273
|
}
|
|
180
274
|
connections.clear();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tcp.js","sourceRoot":"","sources":["../../../src/infrastructure/server/tcp.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,OAAO,EAAE,aAAa,EAAuB,MAAM,WAAW,CAAC;AAC/D,OAAO,EACL,WAAW,EACX,cAAc,EACd,qBAAqB,GAEtB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"tcp.js","sourceRoot":"","sources":["../../../src/infrastructure/server/tcp.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bunqueue",
|
|
3
|
-
"version": "2.7.
|
|
3
|
+
"version": "2.7.20",
|
|
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",
|