vidspotai-shared 1.0.71 → 1.0.73
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"llmCallerGateway.d.ts","sourceRoot":"","sources":["../../../src/services/agent/llmCallerGateway.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EACL,WAAW,EACX,YAAY,EACZ,SAAS,EACT,iBAAiB,EACjB,kBAAkB,EACnB,MAAM,aAAa,CAAC;AAGrB;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,WAAW,aAAa;IAC5B,6DAA6D;IAC7D,OAAO,EAAE,MAAM,CAAC;IAChB,oBAAoB;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,qCAAqC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,4CAA4C;IAC5C,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,mEAAmE;IACnE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4EAA4E;IAC5E,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AA2CD,qBAAa,gBAAiB,YAAW,SAAS;IAMpC,OAAO,CAAC,QAAQ,CAAC,GAAG;IALhC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAe;IACzC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;gBAER,GAAG,EAAE,aAAa;IAOzC,IAAI,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IAkC7C,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,UAAU,EACrC,GAAG,EAAE,iBAAiB,CAAC,CAAC,CAAC,GACxB,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC;IAgEjC,gBAAgB,CAAC,CAAC,SAAS,CAAC,CAAC,UAAU,EACrC,GAAG,EAAE,iBAAiB,CAAC,CAAC,CAAC,GACxB;QACD,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;QAC9B,MAAM,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAC;KACxC;YAqBc,uBAAuB;
|
|
1
|
+
{"version":3,"file":"llmCallerGateway.d.ts","sourceRoot":"","sources":["../../../src/services/agent/llmCallerGateway.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EACL,WAAW,EACX,YAAY,EACZ,SAAS,EACT,iBAAiB,EACjB,kBAAkB,EACnB,MAAM,aAAa,CAAC;AAGrB;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,WAAW,aAAa;IAC5B,6DAA6D;IAC7D,OAAO,EAAE,MAAM,CAAC;IAChB,oBAAoB;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,qCAAqC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,4CAA4C;IAC5C,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,mEAAmE;IACnE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4EAA4E;IAC5E,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AA2CD,qBAAa,gBAAiB,YAAW,SAAS;IAMpC,OAAO,CAAC,QAAQ,CAAC,GAAG;IALhC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAe;IACzC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;gBAER,GAAG,EAAE,aAAa;IAOzC,IAAI,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IAkC7C,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,UAAU,EACrC,GAAG,EAAE,iBAAiB,CAAC,CAAC,CAAC,GACxB,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC;IAgEjC,gBAAgB,CAAC,CAAC,SAAS,CAAC,CAAC,UAAU,EACrC,GAAG,EAAE,iBAAiB,CAAC,CAAC,CAAC,GACxB;QACD,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;QAC9B,MAAM,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAC;KACxC;YAqBc,uBAAuB;IA4ItC,OAAO,CAAC,OAAO;YAID,aAAa;YAqBb,SAAS;IAcvB,OAAO,CAAC,KAAK;IAQb;;;;;OAKG;YACW,aAAa;YAIb,SAAS;YA+BT,QAAQ;CA6BvB"}
|
|
@@ -228,6 +228,14 @@ class GatewayLlmCaller {
|
|
|
228
228
|
}
|
|
229
229
|
}
|
|
230
230
|
}
|
|
231
|
+
// Post-stream failures (bad JSON / schema mismatch) reject the RESULT
|
|
232
|
+
// promise but must NOT throw out of this generator. The tokens already
|
|
233
|
+
// streamed fine; throwing here would propagate into the caller's
|
|
234
|
+
// `for await (...stream.tokens)` loop and abort it before the caller can
|
|
235
|
+
// reach `await stream.result` — which is exactly where the planner's
|
|
236
|
+
// non-streaming retry fallback lives (Planner.planStream). Returning
|
|
237
|
+
// cleanly lets the token loop complete, then the rejected result drives
|
|
238
|
+
// the retry. See plan.controller.ts:planProjectStream.
|
|
231
239
|
let parsed;
|
|
232
240
|
try {
|
|
233
241
|
parsed = JSON.parse(accumulated);
|
|
@@ -235,13 +243,13 @@ class GatewayLlmCaller {
|
|
|
235
243
|
catch {
|
|
236
244
|
const err = new Error(`GatewayLlmCaller.structuredStream: model returned non-JSON for ${req.schemaName}: ${accumulated.slice(0, 200)}`);
|
|
237
245
|
rejectResult(err);
|
|
238
|
-
|
|
246
|
+
return;
|
|
239
247
|
}
|
|
240
248
|
const validated = req.schema.safeParse(parsed);
|
|
241
249
|
if (!validated.success) {
|
|
242
250
|
const err = new Error(`GatewayLlmCaller.structuredStream: schema validation failed for ${req.schemaName}: ${validated.error.message}`);
|
|
243
251
|
rejectResult(err);
|
|
244
|
-
|
|
252
|
+
return;
|
|
245
253
|
}
|
|
246
254
|
resolveResult({
|
|
247
255
|
data: validated.data,
|
|
@@ -10,11 +10,36 @@ declare class BullMQService {
|
|
|
10
10
|
private queues;
|
|
11
11
|
private workers;
|
|
12
12
|
private redisOptions;
|
|
13
|
+
private connection?;
|
|
13
14
|
private concurrency;
|
|
14
15
|
private initialized;
|
|
15
16
|
private shuttingDown;
|
|
16
17
|
private constructor();
|
|
17
18
|
static getInstance(options: BullMQServiceOptions): BullMQService;
|
|
19
|
+
/**
|
|
20
|
+
* Lazily create and return the single shared ioredis connection for this
|
|
21
|
+
* process. ALL Queues and Workers must use this instance rather than a plain
|
|
22
|
+
* options object.
|
|
23
|
+
*
|
|
24
|
+
* WHY THIS EXISTS — Redis client exhaustion:
|
|
25
|
+
* Passing a plain RedisOptions object to `new Queue`/`new Worker` makes
|
|
26
|
+
* BullMQ open a BRAND-NEW connection for every component, so total
|
|
27
|
+
* connections scale as (instances × queues). With 7 queues across N warm
|
|
28
|
+
* Cloud Run instances + the worker fleet, this blew past the Redis
|
|
29
|
+
* `maxclients` cap → "ERR max number of clients reached".
|
|
30
|
+
*
|
|
31
|
+
* Passing a shared IORedis instance instead:
|
|
32
|
+
* - Queues reuse this one connection (0 extra per queue).
|
|
33
|
+
* - Workers reuse it for non-blocking commands and BullMQ internally
|
|
34
|
+
* `.duplicate()`s it for each worker's MANDATORY blocking client
|
|
35
|
+
* (one blocking conn per worker is unavoidable by BullMQ design).
|
|
36
|
+
* Net: a producer (Functions) holds exactly 1 connection regardless of how
|
|
37
|
+
* many queues it enqueues to; a worker host holds 1 + (1 per worker).
|
|
38
|
+
*
|
|
39
|
+
* `maxRetriesPerRequest: null` (in sharedRedisOptions) is REQUIRED by BullMQ
|
|
40
|
+
* for the connection it blocks on.
|
|
41
|
+
*/
|
|
42
|
+
private getConnection;
|
|
18
43
|
/** Initialize BullMQ service (like your initRedis) */
|
|
19
44
|
init(): Promise<void>;
|
|
20
45
|
/** Add a job */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bullmq.service.d.ts","sourceRoot":"","sources":["../../src/services/bullmq.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAiB,GAAG,EAAE,MAAM,QAAQ,CAAC;AAC5C,
|
|
1
|
+
{"version":3,"file":"bullmq.service.d.ts","sourceRoot":"","sources":["../../src/services/bullmq.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAiB,GAAG,EAAE,MAAM,QAAQ,CAAC;AAC5C,OAAgB,EAAwB,YAAY,EAAE,MAAM,SAAS,CAAC;AAItE,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AAE1C,UAAU,oBAAoB;IAC5B,YAAY,EAAE,YAAY,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,cAAM,aAAa;IACjB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAgB;IACvC,OAAO,CAAC,MAAM,CAAiC;IAC/C,OAAO,CAAC,OAAO,CAAgB;IAC/B,OAAO,CAAC,YAAY,CAAgB;IAIpC,OAAO,CAAC,UAAU,CAAC,CAAc;IACjC,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,YAAY,CAAS;IAE7B,OAAO;WAQO,WAAW,CAAC,OAAO,EAAE,oBAAoB;IAOvD;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,OAAO,CAAC,aAAa;IAOrB,sDAAsD;IACzC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAiBlC,gBAAgB;IACH,MAAM,CACjB,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,OAAO,EACb,IAAI,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;IAUpC,YAAY,CACjB,UAAU,EAAE,MAAM,EAAE,EACpB,SAAS,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,EACtC,eAAe,CAAC,EAAE,MAAM,CACtB,MAAM,EACN;QACE,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CACF;CAwGJ;AASD,eAAO,MAAM,MAAM,eAGjB,CAAC;AAEH,MAAM,MAAM,SAAS,GAAG,GAAG,CAAC"}
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.bullmq = void 0;
|
|
4
7
|
// libs/bullmqService.ts
|
|
5
8
|
const bullmq_1 = require("bullmq");
|
|
9
|
+
const ioredis_1 = __importDefault(require("ioredis"));
|
|
6
10
|
const logger_1 = require("../utils/logger");
|
|
7
11
|
const redisOptions_1 = require("./redisOptions");
|
|
8
12
|
class BullMQService {
|
|
@@ -20,19 +24,44 @@ class BullMQService {
|
|
|
20
24
|
}
|
|
21
25
|
return BullMQService.instance;
|
|
22
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* Lazily create and return the single shared ioredis connection for this
|
|
29
|
+
* process. ALL Queues and Workers must use this instance rather than a plain
|
|
30
|
+
* options object.
|
|
31
|
+
*
|
|
32
|
+
* WHY THIS EXISTS — Redis client exhaustion:
|
|
33
|
+
* Passing a plain RedisOptions object to `new Queue`/`new Worker` makes
|
|
34
|
+
* BullMQ open a BRAND-NEW connection for every component, so total
|
|
35
|
+
* connections scale as (instances × queues). With 7 queues across N warm
|
|
36
|
+
* Cloud Run instances + the worker fleet, this blew past the Redis
|
|
37
|
+
* `maxclients` cap → "ERR max number of clients reached".
|
|
38
|
+
*
|
|
39
|
+
* Passing a shared IORedis instance instead:
|
|
40
|
+
* - Queues reuse this one connection (0 extra per queue).
|
|
41
|
+
* - Workers reuse it for non-blocking commands and BullMQ internally
|
|
42
|
+
* `.duplicate()`s it for each worker's MANDATORY blocking client
|
|
43
|
+
* (one blocking conn per worker is unavoidable by BullMQ design).
|
|
44
|
+
* Net: a producer (Functions) holds exactly 1 connection regardless of how
|
|
45
|
+
* many queues it enqueues to; a worker host holds 1 + (1 per worker).
|
|
46
|
+
*
|
|
47
|
+
* `maxRetriesPerRequest: null` (in sharedRedisOptions) is REQUIRED by BullMQ
|
|
48
|
+
* for the connection it blocks on.
|
|
49
|
+
*/
|
|
50
|
+
getConnection() {
|
|
51
|
+
if (this.connection)
|
|
52
|
+
return this.connection;
|
|
53
|
+
this.connection = new ioredis_1.default(this.redisOptions);
|
|
54
|
+
(0, redisOptions_1.attachRedisListeners)(this.connection, "BullMQ");
|
|
55
|
+
return this.connection;
|
|
56
|
+
}
|
|
23
57
|
/** Initialize BullMQ service (like your initRedis) */
|
|
24
58
|
async init() {
|
|
25
59
|
if (this.initialized)
|
|
26
60
|
return;
|
|
27
61
|
try {
|
|
28
|
-
//
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
});
|
|
32
|
-
// Ping Redis via ioredis client
|
|
33
|
-
const testQueueClient = await testQueue.client;
|
|
34
|
-
testQueueClient.ping();
|
|
35
|
-
await testQueue.close();
|
|
62
|
+
// Ping the shared connection directly — no throwaway Queue (which would
|
|
63
|
+
// open, then close, an extra connection on every cold start).
|
|
64
|
+
await this.getConnection().ping();
|
|
36
65
|
this.initialized = true;
|
|
37
66
|
logger_1.logger.info("BullMQService initialized and connected to Redis");
|
|
38
67
|
}
|
|
@@ -48,7 +77,7 @@ class BullMQService {
|
|
|
48
77
|
if (!this.initialized)
|
|
49
78
|
await this.init();
|
|
50
79
|
const queue = this.queues.get(queueName) ??
|
|
51
|
-
new bullmq_1.Queue(queueName, { connection: this.
|
|
80
|
+
new bullmq_1.Queue(queueName, { connection: this.getConnection() });
|
|
52
81
|
this.queues.set(queueName, queue);
|
|
53
82
|
await queue.add(opts?.jobId || "default", data, { delay: opts?.delay });
|
|
54
83
|
}
|
|
@@ -58,11 +87,11 @@ class BullMQService {
|
|
|
58
87
|
await this.init();
|
|
59
88
|
for (const queueName of queueNames) {
|
|
60
89
|
const queue = this.queues.get(queueName) ??
|
|
61
|
-
new bullmq_1.Queue(queueName, { connection: this.
|
|
90
|
+
new bullmq_1.Queue(queueName, { connection: this.getConnection() });
|
|
62
91
|
this.queues.set(queueName, queue);
|
|
63
92
|
const overrides = perQueueOptions?.[queueName] ?? {};
|
|
64
93
|
const worker = new bullmq_1.Worker(queueName, async (job) => processor(job), {
|
|
65
|
-
connection: this.
|
|
94
|
+
connection: this.getConnection(),
|
|
66
95
|
concurrency: overrides.concurrency ?? this.concurrency,
|
|
67
96
|
// N5 (agent refactor Stage 2). Explicit lock semantics:
|
|
68
97
|
// - lockDuration: 60s default. BullMQ auto-renews while the
|
|
@@ -122,6 +151,15 @@ class BullMQService {
|
|
|
122
151
|
await worker.close();
|
|
123
152
|
logger_1.logger.info(`Worker for queue closed`, { queueName: worker.name });
|
|
124
153
|
}
|
|
154
|
+
// Close queues and the shared connection so blocking-client dups are
|
|
155
|
+
// released cleanly (prevents lingering clients on the Redis side after
|
|
156
|
+
// a rolling deploy / SIGTERM on Railway).
|
|
157
|
+
for (const queue of this.queues.values()) {
|
|
158
|
+
await queue.close();
|
|
159
|
+
}
|
|
160
|
+
if (this.connection) {
|
|
161
|
+
await this.connection.quit();
|
|
162
|
+
}
|
|
125
163
|
logger_1.logger.info("All workers closed. Exiting process.");
|
|
126
164
|
process.exit(0);
|
|
127
165
|
};
|