bunqueue 2.6.38 → 2.6.40
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/infrastructure/cloud/buffer.d.ts +18 -0
- package/dist/infrastructure/cloud/buffer.d.ts.map +1 -0
- package/dist/infrastructure/cloud/buffer.js +30 -0
- package/dist/infrastructure/cloud/buffer.js.map +1 -0
- package/dist/infrastructure/cloud/circuitBreaker.d.ts +20 -0
- package/dist/infrastructure/cloud/circuitBreaker.d.ts.map +1 -0
- package/dist/infrastructure/cloud/circuitBreaker.js +47 -0
- package/dist/infrastructure/cloud/circuitBreaker.js.map +1 -0
- package/dist/infrastructure/cloud/cloudAgent.d.ts +39 -0
- package/dist/infrastructure/cloud/cloudAgent.d.ts.map +1 -0
- package/dist/infrastructure/cloud/cloudAgent.js +156 -0
- package/dist/infrastructure/cloud/cloudAgent.js.map +1 -0
- package/dist/infrastructure/cloud/commandHandler.d.ts +34 -0
- package/dist/infrastructure/cloud/commandHandler.d.ts.map +1 -0
- package/dist/infrastructure/cloud/commandHandler.js +101 -0
- package/dist/infrastructure/cloud/commandHandler.js.map +1 -0
- package/dist/infrastructure/cloud/config.d.ts +8 -0
- package/dist/infrastructure/cloud/config.d.ts.map +1 -0
- package/dist/infrastructure/cloud/config.js +31 -0
- package/dist/infrastructure/cloud/config.js.map +1 -0
- package/dist/infrastructure/cloud/httpSender.d.ts +23 -0
- package/dist/infrastructure/cloud/httpSender.d.ts.map +1 -0
- package/dist/infrastructure/cloud/httpSender.js +100 -0
- package/dist/infrastructure/cloud/httpSender.js.map +1 -0
- package/dist/infrastructure/cloud/index.d.ts +11 -0
- package/dist/infrastructure/cloud/index.d.ts.map +1 -0
- package/dist/infrastructure/cloud/index.js +10 -0
- package/dist/infrastructure/cloud/index.js.map +1 -0
- package/dist/infrastructure/cloud/instanceId.d.ts +7 -0
- package/dist/infrastructure/cloud/instanceId.d.ts.map +1 -0
- package/dist/infrastructure/cloud/instanceId.js +34 -0
- package/dist/infrastructure/cloud/instanceId.js.map +1 -0
- package/dist/infrastructure/cloud/logger.d.ts +5 -0
- package/dist/infrastructure/cloud/logger.d.ts.map +1 -0
- package/dist/infrastructure/cloud/logger.js +6 -0
- package/dist/infrastructure/cloud/logger.js.map +1 -0
- package/dist/infrastructure/cloud/snapshotCollector.d.ts +9 -0
- package/dist/infrastructure/cloud/snapshotCollector.d.ts.map +1 -0
- package/dist/infrastructure/cloud/snapshotCollector.js +213 -0
- package/dist/infrastructure/cloud/snapshotCollector.js.map +1 -0
- package/dist/infrastructure/cloud/types.d.ts +210 -0
- package/dist/infrastructure/cloud/types.d.ts.map +1 -0
- package/dist/infrastructure/cloud/types.js +6 -0
- package/dist/infrastructure/cloud/types.js.map +1 -0
- package/dist/infrastructure/cloud/wsSender.d.ts +31 -0
- package/dist/infrastructure/cloud/wsSender.d.ts.map +1 -0
- package/dist/infrastructure/cloud/wsSender.js +121 -0
- package/dist/infrastructure/cloud/wsSender.js.map +1 -0
- package/dist/main.js +8 -0
- package/dist/main.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Snapshot Buffer
|
|
3
|
+
* Stores snapshots locally when the dashboard is unreachable.
|
|
4
|
+
* On reconnect, flushes buffered data so the dashboard fills historical gaps.
|
|
5
|
+
*/
|
|
6
|
+
import type { CloudSnapshot } from './types';
|
|
7
|
+
export declare class SnapshotBuffer {
|
|
8
|
+
private readonly maxSize;
|
|
9
|
+
private readonly items;
|
|
10
|
+
constructor(maxSize: number);
|
|
11
|
+
/** Add a snapshot. Drops oldest if full. */
|
|
12
|
+
push(snapshot: CloudSnapshot): void;
|
|
13
|
+
/** Drain up to `count` snapshots for sending */
|
|
14
|
+
drain(count: number): CloudSnapshot[];
|
|
15
|
+
get size(): number;
|
|
16
|
+
get isEmpty(): boolean;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=buffer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buffer.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/cloud/buffer.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAE7C,qBAAa,cAAc;IAGb,OAAO,CAAC,QAAQ,CAAC,OAAO;IAFpC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAuB;gBAEhB,OAAO,EAAE,MAAM;IAE5C,4CAA4C;IAC5C,IAAI,CAAC,QAAQ,EAAE,aAAa,GAAG,IAAI;IAOnC,gDAAgD;IAChD,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,EAAE;IAIrC,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,IAAI,OAAO,IAAI,OAAO,CAErB;CACF"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Snapshot Buffer
|
|
3
|
+
* Stores snapshots locally when the dashboard is unreachable.
|
|
4
|
+
* On reconnect, flushes buffered data so the dashboard fills historical gaps.
|
|
5
|
+
*/
|
|
6
|
+
export class SnapshotBuffer {
|
|
7
|
+
maxSize;
|
|
8
|
+
items = [];
|
|
9
|
+
constructor(maxSize) {
|
|
10
|
+
this.maxSize = maxSize;
|
|
11
|
+
}
|
|
12
|
+
/** Add a snapshot. Drops oldest if full. */
|
|
13
|
+
push(snapshot) {
|
|
14
|
+
if (this.items.length >= this.maxSize) {
|
|
15
|
+
this.items.shift();
|
|
16
|
+
}
|
|
17
|
+
this.items.push(snapshot);
|
|
18
|
+
}
|
|
19
|
+
/** Drain up to `count` snapshots for sending */
|
|
20
|
+
drain(count) {
|
|
21
|
+
return this.items.splice(0, Math.min(count, this.items.length));
|
|
22
|
+
}
|
|
23
|
+
get size() {
|
|
24
|
+
return this.items.length;
|
|
25
|
+
}
|
|
26
|
+
get isEmpty() {
|
|
27
|
+
return this.items.length === 0;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=buffer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buffer.js","sourceRoot":"","sources":["../../../src/infrastructure/cloud/buffer.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,MAAM,OAAO,cAAc;IAGI;IAFZ,KAAK,GAAoB,EAAE,CAAC;IAE7C,YAA6B,OAAe;QAAf,YAAO,GAAP,OAAO,CAAQ;IAAG,CAAC;IAEhD,4CAA4C;IAC5C,IAAI,CAAC,QAAuB;QAC1B,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACtC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACrB,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC5B,CAAC;IAED,gDAAgD;IAChD,KAAK,CAAC,KAAa;QACjB,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;IAClE,CAAC;IAED,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;IAC3B,CAAC;IAED,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC;IACjC,CAAC;CACF"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Circuit Breaker
|
|
3
|
+
* Prevents hammering a dead endpoint. States: CLOSED → OPEN → HALF_OPEN → CLOSED
|
|
4
|
+
*/
|
|
5
|
+
export declare class CircuitBreaker {
|
|
6
|
+
private readonly threshold;
|
|
7
|
+
private readonly resetMs;
|
|
8
|
+
private state;
|
|
9
|
+
private failures;
|
|
10
|
+
private openedAt;
|
|
11
|
+
constructor(threshold: number, resetMs: number);
|
|
12
|
+
/** Check if a request is allowed */
|
|
13
|
+
canExecute(): boolean;
|
|
14
|
+
/** Record a successful call */
|
|
15
|
+
onSuccess(): void;
|
|
16
|
+
/** Record a failed call */
|
|
17
|
+
onFailure(): void;
|
|
18
|
+
getState(): string;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=circuitBreaker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"circuitBreaker.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/cloud/circuitBreaker.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,qBAAa,cAAc;IAMvB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,OAAO;IAN1B,OAAO,CAAC,KAAK,CAAmB;IAChC,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,QAAQ,CAAK;gBAGF,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM;IAGlC,oCAAoC;IACpC,UAAU,IAAI,OAAO;IAgBrB,+BAA+B;IAC/B,SAAS,IAAI,IAAI;IAKjB,2BAA2B;IAC3B,SAAS,IAAI,IAAI;IAQjB,QAAQ,IAAI,MAAM;CAGnB"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Circuit Breaker
|
|
3
|
+
* Prevents hammering a dead endpoint. States: CLOSED → OPEN → HALF_OPEN → CLOSED
|
|
4
|
+
*/
|
|
5
|
+
export class CircuitBreaker {
|
|
6
|
+
threshold;
|
|
7
|
+
resetMs;
|
|
8
|
+
state = 'closed';
|
|
9
|
+
failures = 0;
|
|
10
|
+
openedAt = 0;
|
|
11
|
+
constructor(threshold, resetMs) {
|
|
12
|
+
this.threshold = threshold;
|
|
13
|
+
this.resetMs = resetMs;
|
|
14
|
+
}
|
|
15
|
+
/** Check if a request is allowed */
|
|
16
|
+
canExecute() {
|
|
17
|
+
if (this.state === 'closed')
|
|
18
|
+
return true;
|
|
19
|
+
if (this.state === 'open') {
|
|
20
|
+
// Check if enough time passed to try again
|
|
21
|
+
if (Date.now() - this.openedAt >= this.resetMs) {
|
|
22
|
+
this.state = 'half_open';
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
// half_open: allow one request through
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
/** Record a successful call */
|
|
31
|
+
onSuccess() {
|
|
32
|
+
this.failures = 0;
|
|
33
|
+
this.state = 'closed';
|
|
34
|
+
}
|
|
35
|
+
/** Record a failed call */
|
|
36
|
+
onFailure() {
|
|
37
|
+
this.failures++;
|
|
38
|
+
if (this.state === 'half_open' || this.failures >= this.threshold) {
|
|
39
|
+
this.state = 'open';
|
|
40
|
+
this.openedAt = Date.now();
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
getState() {
|
|
44
|
+
return this.state;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=circuitBreaker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"circuitBreaker.js","sourceRoot":"","sources":["../../../src/infrastructure/cloud/circuitBreaker.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,MAAM,OAAO,cAAc;IAMN;IACA;IANX,KAAK,GAAU,QAAQ,CAAC;IACxB,QAAQ,GAAG,CAAC,CAAC;IACb,QAAQ,GAAG,CAAC,CAAC;IAErB,YACmB,SAAiB,EACjB,OAAe;QADf,cAAS,GAAT,SAAS,CAAQ;QACjB,YAAO,GAAP,OAAO,CAAQ;IAC/B,CAAC;IAEJ,oCAAoC;IACpC,UAAU;QACR,IAAI,IAAI,CAAC,KAAK,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC;QAEzC,IAAI,IAAI,CAAC,KAAK,KAAK,MAAM,EAAE,CAAC;YAC1B,2CAA2C;YAC3C,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;gBAC/C,IAAI,CAAC,KAAK,GAAG,WAAW,CAAC;gBACzB,OAAO,IAAI,CAAC;YACd,CAAC;YACD,OAAO,KAAK,CAAC;QACf,CAAC;QAED,uCAAuC;QACvC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,+BAA+B;IAC/B,SAAS;QACP,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC;QAClB,IAAI,CAAC,KAAK,GAAG,QAAQ,CAAC;IACxB,CAAC;IAED,2BAA2B;IAC3B,SAAS;QACP,IAAI,CAAC,QAAQ,EAAE,CAAC;QAChB,IAAI,IAAI,CAAC,KAAK,KAAK,WAAW,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YAClE,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC;YACpB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,CAAC;IACH,CAAC;IAED,QAAQ;QACN,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;CACF"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* bunqueue Cloud Agent
|
|
3
|
+
* Main orchestrator that collects telemetry and sends it to bunqueue Cloud.
|
|
4
|
+
*
|
|
5
|
+
* Two channels:
|
|
6
|
+
* 1. HTTP POST (periodic snapshots every N seconds)
|
|
7
|
+
* 2. WebSocket (real-time event forwarding)
|
|
8
|
+
*
|
|
9
|
+
* Zero overhead when disabled (BUNQUEUE_CLOUD_URL not set).
|
|
10
|
+
*/
|
|
11
|
+
import type { QueueManager } from '../../application/queueManager';
|
|
12
|
+
import type { CloudConfig } from './types';
|
|
13
|
+
export declare class CloudAgent {
|
|
14
|
+
private readonly queueManager;
|
|
15
|
+
private readonly config;
|
|
16
|
+
private readonly instanceId;
|
|
17
|
+
private readonly startedAt;
|
|
18
|
+
private readonly httpSender;
|
|
19
|
+
private readonly wsSender;
|
|
20
|
+
private snapshotTimer;
|
|
21
|
+
private unsubscribeEvents;
|
|
22
|
+
private sequenceId;
|
|
23
|
+
private stopped;
|
|
24
|
+
constructor(queueManager: QueueManager, config: CloudConfig);
|
|
25
|
+
/** Create and start a Cloud agent if configured. Returns null if disabled. */
|
|
26
|
+
static create(queueManager: QueueManager, dataPath?: string): CloudAgent | null;
|
|
27
|
+
/** Start both channels */
|
|
28
|
+
start(): void;
|
|
29
|
+
/** Graceful shutdown: send final snapshot, close connections */
|
|
30
|
+
stop(): Promise<void>;
|
|
31
|
+
/** Collect and send a snapshot */
|
|
32
|
+
private sendSnapshot;
|
|
33
|
+
/** Subscribe to job events for WebSocket forwarding */
|
|
34
|
+
private subscribeToEvents;
|
|
35
|
+
/** Redact sensitive fields from job data */
|
|
36
|
+
private redactData;
|
|
37
|
+
getInstanceId(): string;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=cloudAgent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloudAgent.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/cloud/cloudAgent.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAEnE,OAAO,KAAK,EAAE,WAAW,EAAc,MAAM,SAAS,CAAC;AASvD,qBAAa,UAAU;IAYnB,OAAO,CAAC,QAAQ,CAAC,YAAY;IAX/B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAc;IACrC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAc;IACxC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAa;IACxC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAkB;IAC3C,OAAO,CAAC,aAAa,CAA+C;IACpE,OAAO,CAAC,iBAAiB,CAA6B;IACtD,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,OAAO,CAAS;gBAGL,YAAY,EAAE,YAAY,EAC3C,MAAM,EAAE,WAAW;IAQrB,8EAA8E;IAC9E,MAAM,CAAC,MAAM,CAAC,YAAY,EAAE,YAAY,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI;IAS/E,0BAA0B;IAC1B,KAAK,IAAI,IAAI;IAqCb,gEAAgE;IAC1D,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAkC3B,kCAAkC;YACpB,YAAY;IAe1B,uDAAuD;IACvD,OAAO,CAAC,iBAAiB;IA6BzB,4CAA4C;IAC5C,OAAO,CAAC,UAAU;IAclB,aAAa,IAAI,MAAM;CAGxB"}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* bunqueue Cloud Agent
|
|
3
|
+
* Main orchestrator that collects telemetry and sends it to bunqueue Cloud.
|
|
4
|
+
*
|
|
5
|
+
* Two channels:
|
|
6
|
+
* 1. HTTP POST (periodic snapshots every N seconds)
|
|
7
|
+
* 2. WebSocket (real-time event forwarding)
|
|
8
|
+
*
|
|
9
|
+
* Zero overhead when disabled (BUNQUEUE_CLOUD_URL not set).
|
|
10
|
+
*/
|
|
11
|
+
import { loadCloudConfig } from './config';
|
|
12
|
+
import { getInstanceId } from './instanceId';
|
|
13
|
+
import { collectSnapshot } from './snapshotCollector';
|
|
14
|
+
import { HttpSender } from './httpSender';
|
|
15
|
+
import { WsSender } from './wsSender';
|
|
16
|
+
import { handleCommand } from './commandHandler';
|
|
17
|
+
import { cloudLog } from './logger';
|
|
18
|
+
export class CloudAgent {
|
|
19
|
+
queueManager;
|
|
20
|
+
config;
|
|
21
|
+
instanceId;
|
|
22
|
+
startedAt = Date.now();
|
|
23
|
+
httpSender;
|
|
24
|
+
wsSender;
|
|
25
|
+
snapshotTimer = null;
|
|
26
|
+
unsubscribeEvents = null;
|
|
27
|
+
sequenceId = 0;
|
|
28
|
+
stopped = false;
|
|
29
|
+
constructor(queueManager, config) {
|
|
30
|
+
this.queueManager = queueManager;
|
|
31
|
+
this.config = config;
|
|
32
|
+
this.instanceId = getInstanceId(config.dataPath);
|
|
33
|
+
this.httpSender = new HttpSender(config);
|
|
34
|
+
this.wsSender = config.useWebSocket ? new WsSender(config, this.instanceId) : null;
|
|
35
|
+
}
|
|
36
|
+
/** Create and start a Cloud agent if configured. Returns null if disabled. */
|
|
37
|
+
static create(queueManager, dataPath) {
|
|
38
|
+
const config = loadCloudConfig(dataPath);
|
|
39
|
+
if (!config)
|
|
40
|
+
return null;
|
|
41
|
+
const agent = new CloudAgent(queueManager, config);
|
|
42
|
+
agent.start();
|
|
43
|
+
return agent;
|
|
44
|
+
}
|
|
45
|
+
/** Start both channels */
|
|
46
|
+
start() {
|
|
47
|
+
cloudLog.info('Connecting to dashboard', {
|
|
48
|
+
url: this.config.url,
|
|
49
|
+
instance: this.config.instanceName,
|
|
50
|
+
id: this.instanceId,
|
|
51
|
+
intervalMs: this.config.intervalMs,
|
|
52
|
+
ws: this.config.useWebSocket,
|
|
53
|
+
});
|
|
54
|
+
// Channel 1: HTTP snapshots
|
|
55
|
+
if (this.config.useHttp) {
|
|
56
|
+
// Send first snapshot immediately
|
|
57
|
+
void this.sendSnapshot();
|
|
58
|
+
this.snapshotTimer = setInterval(() => {
|
|
59
|
+
void this.sendSnapshot();
|
|
60
|
+
}, this.config.intervalMs);
|
|
61
|
+
}
|
|
62
|
+
// Channel 2: WebSocket events + remote commands
|
|
63
|
+
if (this.wsSender) {
|
|
64
|
+
// Register command handler if remote commands enabled
|
|
65
|
+
if (this.config.remoteCommands) {
|
|
66
|
+
cloudLog.info('Remote commands enabled');
|
|
67
|
+
this.wsSender.setCommandHandler((cmd) => {
|
|
68
|
+
handleCommand(this.queueManager, cmd)
|
|
69
|
+
.then((result) => this.wsSender?.sendRaw(result))
|
|
70
|
+
.catch((err) => {
|
|
71
|
+
cloudLog.debug('Command handler error', { error: String(err) });
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
this.wsSender.connect();
|
|
76
|
+
this.subscribeToEvents();
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/** Graceful shutdown: send final snapshot, close connections */
|
|
80
|
+
async stop() {
|
|
81
|
+
if (this.stopped)
|
|
82
|
+
return;
|
|
83
|
+
this.stopped = true;
|
|
84
|
+
if (this.snapshotTimer) {
|
|
85
|
+
clearInterval(this.snapshotTimer);
|
|
86
|
+
this.snapshotTimer = null;
|
|
87
|
+
}
|
|
88
|
+
if (this.unsubscribeEvents) {
|
|
89
|
+
this.unsubscribeEvents();
|
|
90
|
+
this.unsubscribeEvents = null;
|
|
91
|
+
}
|
|
92
|
+
// Send final shutdown snapshot (best-effort, 2s timeout)
|
|
93
|
+
try {
|
|
94
|
+
const snapshot = collectSnapshot(this.queueManager, this.instanceId, this.config.instanceName, this.startedAt, ++this.sequenceId);
|
|
95
|
+
snapshot.shutdown = true;
|
|
96
|
+
await Promise.race([this.httpSender.send(snapshot), Bun.sleep(2000)]);
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
// Best-effort
|
|
100
|
+
}
|
|
101
|
+
this.wsSender?.stop();
|
|
102
|
+
cloudLog.info('Disconnected from dashboard');
|
|
103
|
+
}
|
|
104
|
+
/** Collect and send a snapshot */
|
|
105
|
+
async sendSnapshot() {
|
|
106
|
+
try {
|
|
107
|
+
const snapshot = collectSnapshot(this.queueManager, this.instanceId, this.config.instanceName, this.startedAt, ++this.sequenceId);
|
|
108
|
+
await this.httpSender.send(snapshot);
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
cloudLog.debug('Snapshot send failed', { error: String(err) });
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/** Subscribe to job events for WebSocket forwarding */
|
|
115
|
+
subscribeToEvents() {
|
|
116
|
+
this.unsubscribeEvents = this.queueManager.subscribe((event) => {
|
|
117
|
+
if (!this.wsSender)
|
|
118
|
+
return;
|
|
119
|
+
// Apply event filter
|
|
120
|
+
if (this.config.eventFilter.length > 0 &&
|
|
121
|
+
!this.config.eventFilter.includes(event.eventType)) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
const cloudEvent = {
|
|
125
|
+
instanceId: this.instanceId,
|
|
126
|
+
timestamp: event.timestamp,
|
|
127
|
+
jobEvent: {
|
|
128
|
+
eventType: event.eventType,
|
|
129
|
+
queue: event.queue,
|
|
130
|
+
jobId: event.jobId,
|
|
131
|
+
error: event.error,
|
|
132
|
+
progress: event.progress,
|
|
133
|
+
data: this.config.includeJobData ? this.redactData(event.data) : undefined,
|
|
134
|
+
},
|
|
135
|
+
};
|
|
136
|
+
this.wsSender.send(cloudEvent);
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
/** Redact sensitive fields from job data */
|
|
140
|
+
redactData(data) {
|
|
141
|
+
if (!data || typeof data !== 'object' || this.config.redactFields.length === 0) {
|
|
142
|
+
return data;
|
|
143
|
+
}
|
|
144
|
+
const redacted = { ...data };
|
|
145
|
+
for (const field of this.config.redactFields) {
|
|
146
|
+
if (field in redacted) {
|
|
147
|
+
redacted[field] = '[REDACTED]';
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return redacted;
|
|
151
|
+
}
|
|
152
|
+
getInstanceId() {
|
|
153
|
+
return this.instanceId;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=cloudAgent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloudAgent.js","sourceRoot":"","sources":["../../../src/infrastructure/cloud/cloudAgent.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cloud Command Handler
|
|
3
|
+
* Processes commands received from the dashboard via WebSocket.
|
|
4
|
+
* Only active when BUNQUEUE_CLOUD_REMOTE_COMMANDS=true.
|
|
5
|
+
*
|
|
6
|
+
* All commands are whitelisted — unknown actions are rejected.
|
|
7
|
+
*/
|
|
8
|
+
import type { QueueManager } from '../../application/queueManager';
|
|
9
|
+
/** Incoming command from dashboard (fields at top level) */
|
|
10
|
+
export interface CloudCommand {
|
|
11
|
+
type: 'command';
|
|
12
|
+
id: string;
|
|
13
|
+
action: string;
|
|
14
|
+
queue?: string;
|
|
15
|
+
jobId?: string;
|
|
16
|
+
name?: string;
|
|
17
|
+
schedule?: string;
|
|
18
|
+
data?: unknown;
|
|
19
|
+
config?: Record<string, unknown>;
|
|
20
|
+
graceMs?: number;
|
|
21
|
+
state?: string;
|
|
22
|
+
limit?: number;
|
|
23
|
+
}
|
|
24
|
+
/** Result sent back to dashboard */
|
|
25
|
+
export interface CloudCommandResult {
|
|
26
|
+
type: 'command_result';
|
|
27
|
+
id: string;
|
|
28
|
+
success: boolean;
|
|
29
|
+
data?: unknown;
|
|
30
|
+
error?: string;
|
|
31
|
+
}
|
|
32
|
+
/** Process a command and return the result */
|
|
33
|
+
export declare function handleCommand(queueManager: QueueManager, cmd: CloudCommand): Promise<CloudCommandResult>;
|
|
34
|
+
//# sourceMappingURL=commandHandler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commandHandler.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/cloud/commandHandler.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAInE,4DAA4D;AAC5D,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,SAAS,CAAC;IAChB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,oCAAoC;AACpC,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,gBAAgB,CAAC;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA4ED,8CAA8C;AAC9C,wBAAsB,aAAa,CACjC,YAAY,EAAE,YAAY,EAC1B,GAAG,EAAE,YAAY,GAChB,OAAO,CAAC,kBAAkB,CAAC,CA8B7B"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cloud Command Handler
|
|
3
|
+
* Processes commands received from the dashboard via WebSocket.
|
|
4
|
+
* Only active when BUNQUEUE_CLOUD_REMOTE_COMMANDS=true.
|
|
5
|
+
*
|
|
6
|
+
* All commands are whitelisted — unknown actions are rejected.
|
|
7
|
+
*/
|
|
8
|
+
import { jobId } from '../../domain/types/job';
|
|
9
|
+
import { cloudLog } from './logger';
|
|
10
|
+
/** Whitelisted commands */
|
|
11
|
+
const COMMANDS = {
|
|
12
|
+
'queue:pause': (qm, cmd) => {
|
|
13
|
+
qm.pause(cmd.queue ?? '');
|
|
14
|
+
return { queue: cmd.queue, paused: true };
|
|
15
|
+
},
|
|
16
|
+
'queue:resume': (qm, cmd) => {
|
|
17
|
+
qm.resume(cmd.queue ?? '');
|
|
18
|
+
return { queue: cmd.queue, paused: false };
|
|
19
|
+
},
|
|
20
|
+
'queue:drain': (qm, cmd) => {
|
|
21
|
+
const count = qm.drain(cmd.queue ?? '');
|
|
22
|
+
return { queue: cmd.queue, drained: count };
|
|
23
|
+
},
|
|
24
|
+
'queue:clean': (qm, cmd) => {
|
|
25
|
+
const count = qm.clean(cmd.queue ?? '', cmd.graceMs ?? 0, cmd.state, cmd.limit);
|
|
26
|
+
return { queue: cmd.queue, cleaned: count };
|
|
27
|
+
},
|
|
28
|
+
'job:cancel': async (qm, cmd) => {
|
|
29
|
+
const ok = await qm.cancel(jobId(cmd.jobId ?? ''));
|
|
30
|
+
return { cancelled: ok };
|
|
31
|
+
},
|
|
32
|
+
'job:promote': async (qm, cmd) => {
|
|
33
|
+
const ok = await qm.promote(jobId(cmd.jobId ?? ''));
|
|
34
|
+
return { promoted: ok };
|
|
35
|
+
},
|
|
36
|
+
'job:retry': (qm, cmd) => {
|
|
37
|
+
if (cmd.queue) {
|
|
38
|
+
const count = qm.retryDlq(cmd.queue, cmd.jobId ? jobId(cmd.jobId) : undefined);
|
|
39
|
+
return { retried: count };
|
|
40
|
+
}
|
|
41
|
+
return { retried: 0 };
|
|
42
|
+
},
|
|
43
|
+
'dlq:retry': (qm, cmd) => {
|
|
44
|
+
const count = qm.retryDlq(cmd.queue ?? '', cmd.jobId ? jobId(cmd.jobId) : undefined);
|
|
45
|
+
return { retried: count };
|
|
46
|
+
},
|
|
47
|
+
'dlq:purge': (qm, cmd) => {
|
|
48
|
+
const count = qm.purgeDlq(cmd.queue ?? '');
|
|
49
|
+
return { purged: count };
|
|
50
|
+
},
|
|
51
|
+
'cron:upsert': (qm, cmd) => {
|
|
52
|
+
// Remove existing if any, then add
|
|
53
|
+
qm.removeCron(cmd.name ?? '');
|
|
54
|
+
const cron = qm.addCron({
|
|
55
|
+
name: cmd.name ?? '',
|
|
56
|
+
queue: cmd.queue ?? '',
|
|
57
|
+
data: cmd.data ?? {},
|
|
58
|
+
schedule: cmd.schedule,
|
|
59
|
+
});
|
|
60
|
+
return { name: cron.name, nextRun: cron.nextRun };
|
|
61
|
+
},
|
|
62
|
+
'cron:delete': (qm, cmd) => {
|
|
63
|
+
const ok = qm.removeCron(cmd.name ?? '');
|
|
64
|
+
return { deleted: ok };
|
|
65
|
+
},
|
|
66
|
+
'stats:refresh': (qm) => {
|
|
67
|
+
return qm.getStats();
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
/** Process a command and return the result */
|
|
71
|
+
export async function handleCommand(queueManager, cmd) {
|
|
72
|
+
const handler = COMMANDS[cmd.action];
|
|
73
|
+
if (!handler) {
|
|
74
|
+
cloudLog.warn('Unknown remote command', { action: cmd.action, id: cmd.id });
|
|
75
|
+
return {
|
|
76
|
+
type: 'command_result',
|
|
77
|
+
id: cmd.id,
|
|
78
|
+
success: false,
|
|
79
|
+
error: `Unknown command: ${cmd.action}`,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
try {
|
|
83
|
+
const data = await handler(queueManager, cmd);
|
|
84
|
+
cloudLog.info('Remote command executed', { action: cmd.action, id: cmd.id });
|
|
85
|
+
return { type: 'command_result', id: cmd.id, success: true, data };
|
|
86
|
+
}
|
|
87
|
+
catch (err) {
|
|
88
|
+
cloudLog.error('Remote command failed', {
|
|
89
|
+
action: cmd.action,
|
|
90
|
+
id: cmd.id,
|
|
91
|
+
error: String(err),
|
|
92
|
+
});
|
|
93
|
+
return {
|
|
94
|
+
type: 'command_result',
|
|
95
|
+
id: cmd.id,
|
|
96
|
+
success: false,
|
|
97
|
+
error: err instanceof Error ? err.message : String(err),
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=commandHandler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commandHandler.js","sourceRoot":"","sources":["../../../src/infrastructure/cloud/commandHandler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* bunqueue Cloud Configuration
|
|
3
|
+
* Parses environment variables for Cloud agent
|
|
4
|
+
*/
|
|
5
|
+
import type { CloudConfig } from './types';
|
|
6
|
+
/** Parse Cloud configuration from environment. Returns null if disabled. */
|
|
7
|
+
export declare function loadCloudConfig(dataPath?: string): CloudConfig | null;
|
|
8
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/cloud/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAG3C,4EAA4E;AAC5E,wBAAgB,eAAe,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAwBrE"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* bunqueue Cloud Configuration
|
|
3
|
+
* Parses environment variables for Cloud agent
|
|
4
|
+
*/
|
|
5
|
+
import { hostname } from 'os';
|
|
6
|
+
/** Parse Cloud configuration from environment. Returns null if disabled. */
|
|
7
|
+
export function loadCloudConfig(dataPath) {
|
|
8
|
+
const url = Bun.env.BUNQUEUE_CLOUD_URL;
|
|
9
|
+
const apiKey = Bun.env.BUNQUEUE_CLOUD_API_KEY;
|
|
10
|
+
// Both URL and API key required to enable
|
|
11
|
+
if (!url || !apiKey)
|
|
12
|
+
return null;
|
|
13
|
+
return {
|
|
14
|
+
url: url.replace(/\/+$/, ''), // Strip trailing slashes
|
|
15
|
+
apiKey,
|
|
16
|
+
signingSecret: Bun.env.BUNQUEUE_CLOUD_SIGNING_SECRET ?? null,
|
|
17
|
+
instanceName: Bun.env.BUNQUEUE_CLOUD_INSTANCE_NAME ?? hostname(),
|
|
18
|
+
intervalMs: parseInt(Bun.env.BUNQUEUE_CLOUD_INTERVAL_MS ?? '5000', 10),
|
|
19
|
+
includeJobData: Bun.env.BUNQUEUE_CLOUD_INCLUDE_JOB_DATA === 'true',
|
|
20
|
+
redactFields: Bun.env.BUNQUEUE_CLOUD_REDACT_FIELDS?.split(',').filter(Boolean) ?? [],
|
|
21
|
+
eventFilter: Bun.env.BUNQUEUE_CLOUD_EVENTS?.split(',').filter(Boolean) ?? [],
|
|
22
|
+
bufferSize: parseInt(Bun.env.BUNQUEUE_CLOUD_BUFFER_SIZE ?? '720', 10),
|
|
23
|
+
circuitBreakerThreshold: parseInt(Bun.env.BUNQUEUE_CLOUD_CIRCUIT_BREAKER_THRESHOLD ?? '5', 10),
|
|
24
|
+
circuitBreakerResetMs: parseInt(Bun.env.BUNQUEUE_CLOUD_CIRCUIT_BREAKER_RESET_MS ?? '60000', 10),
|
|
25
|
+
useWebSocket: Bun.env.BUNQUEUE_CLOUD_USE_WEBSOCKET !== 'false',
|
|
26
|
+
useHttp: Bun.env.BUNQUEUE_CLOUD_USE_HTTP !== 'false',
|
|
27
|
+
dataPath: dataPath ?? null,
|
|
28
|
+
remoteCommands: Bun.env.BUNQUEUE_CLOUD_REMOTE_COMMANDS === 'true',
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/infrastructure/cloud/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,QAAQ,EAAE,MAAM,IAAI,CAAC;AAE9B,4EAA4E;AAC5E,MAAM,UAAU,eAAe,CAAC,QAAiB;IAC/C,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,kBAAkB,CAAC;IACvC,MAAM,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC,sBAAsB,CAAC;IAE9C,0CAA0C;IAC1C,IAAI,CAAC,GAAG,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IAEjC,OAAO;QACL,GAAG,EAAE,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE,yBAAyB;QACvD,MAAM;QACN,aAAa,EAAE,GAAG,CAAC,GAAG,CAAC,6BAA6B,IAAI,IAAI;QAC5D,YAAY,EAAE,GAAG,CAAC,GAAG,CAAC,4BAA4B,IAAI,QAAQ,EAAE;QAChE,UAAU,EAAE,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,0BAA0B,IAAI,MAAM,EAAE,EAAE,CAAC;QACtE,cAAc,EAAE,GAAG,CAAC,GAAG,CAAC,+BAA+B,KAAK,MAAM;QAClE,YAAY,EAAE,GAAG,CAAC,GAAG,CAAC,4BAA4B,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE;QACpF,WAAW,EAAE,GAAG,CAAC,GAAG,CAAC,qBAAqB,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE;QAC5E,UAAU,EAAE,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,0BAA0B,IAAI,KAAK,EAAE,EAAE,CAAC;QACrE,uBAAuB,EAAE,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,wCAAwC,IAAI,GAAG,EAAE,EAAE,CAAC;QAC9F,qBAAqB,EAAE,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,uCAAuC,IAAI,OAAO,EAAE,EAAE,CAAC;QAC/F,YAAY,EAAE,GAAG,CAAC,GAAG,CAAC,4BAA4B,KAAK,OAAO;QAC9D,OAAO,EAAE,GAAG,CAAC,GAAG,CAAC,uBAAuB,KAAK,OAAO;QACpD,QAAQ,EAAE,QAAQ,IAAI,IAAI;QAC1B,cAAc,EAAE,GAAG,CAAC,GAAG,CAAC,8BAA8B,KAAK,MAAM;KAClE,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP Sender
|
|
3
|
+
* Posts snapshots to the remote dashboard via HTTP with retry and HMAC signing
|
|
4
|
+
*/
|
|
5
|
+
import type { CloudConfig, CloudSnapshot } from './types';
|
|
6
|
+
export declare class HttpSender {
|
|
7
|
+
private readonly config;
|
|
8
|
+
private readonly circuitBreaker;
|
|
9
|
+
private readonly buffer;
|
|
10
|
+
private readonly ingestUrl;
|
|
11
|
+
private readonly batchUrl;
|
|
12
|
+
private hmacKey;
|
|
13
|
+
constructor(config: CloudConfig);
|
|
14
|
+
/** Send a snapshot. Buffers on failure. */
|
|
15
|
+
send(snapshot: CloudSnapshot): Promise<void>;
|
|
16
|
+
/** Try to send buffered snapshots in batches */
|
|
17
|
+
private flushBuffer;
|
|
18
|
+
/** HTTP POST with auth headers and optional HMAC */
|
|
19
|
+
private post;
|
|
20
|
+
getBufferSize(): number;
|
|
21
|
+
getCircuitState(): string;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=httpSender.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"httpSender.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/cloud/httpSender.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAK1D,qBAAa,UAAU;IAOT,OAAO,CAAC,QAAQ,CAAC,MAAM;IANnC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAiB;IAChD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiB;IACxC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,OAAO,CAA0B;gBAEZ,MAAM,EAAE,WAAW;IAUhD,2CAA2C;IACrC,IAAI,CAAC,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAyBlD,gDAAgD;YAClC,WAAW;IAsBzB,oDAAoD;YACtC,IAAI;IAiClB,aAAa,IAAI,MAAM;IAIvB,eAAe,IAAI,MAAM;CAG1B"}
|