@open-mercato/cli 0.6.5-develop.5337.1.534b781eac → 0.6.5
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/.turbo/turbo-build.log +1 -1
- package/dist/agentic/shared/ai/skills/om-troubleshooter/SKILL.md +40 -17
- package/dist/lib/generators/extensions/ai-agents.js.map +1 -1
- package/dist/lib/generators/extensions/ai-tools.js.map +1 -1
- package/dist/lib/single-instance-strategy-guard.js +89 -0
- package/dist/lib/single-instance-strategy-guard.js.map +7 -0
- package/dist/lib/testing/integration.js +1 -1
- package/dist/lib/testing/integration.js.map +2 -2
- package/dist/lib/worker-job-handler.js +20 -0
- package/dist/lib/worker-job-handler.js.map +7 -0
- package/dist/mercato.js +5 -12
- package/dist/mercato.js.map +2 -2
- package/package.json +8 -9
- package/src/lib/__tests__/single-instance-strategy-guard.test.ts +138 -0
- package/src/lib/__tests__/worker-job-handler.test.ts +135 -0
- package/src/lib/generators/extensions/ai-agents.ts +1 -1
- package/src/lib/generators/extensions/ai-tools.ts +1 -1
- package/src/lib/single-instance-strategy-guard.ts +172 -0
- package/src/lib/testing/integration.ts +1 -1
- package/src/lib/worker-job-handler.ts +45 -0
- package/src/mercato.ts +7 -12
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
function createPerJobWorkerHandler(workers, createContainer) {
|
|
2
|
+
return async (job, ctx) => {
|
|
3
|
+
const container = await createContainer();
|
|
4
|
+
try {
|
|
5
|
+
for (const worker of workers) {
|
|
6
|
+
await worker.handler(job, { ...ctx, resolve: container.resolve.bind(container) });
|
|
7
|
+
}
|
|
8
|
+
} finally {
|
|
9
|
+
try {
|
|
10
|
+
const em = container.resolve("em");
|
|
11
|
+
em?.clear?.();
|
|
12
|
+
} catch {
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export {
|
|
18
|
+
createPerJobWorkerHandler
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=worker-job-handler.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/lib/worker-job-handler.ts"],
|
|
4
|
+
"sourcesContent": ["import type { JobContext, JobHandler } from '@open-mercato/queue'\nimport type { ModuleWorker } from '@open-mercato/shared/modules/registry'\n\nexport type WorkerJobContainer = {\n resolve: <T = unknown>(name: string) => T\n}\n\nexport type WorkerJobContainerFactory = () => Promise<WorkerJobContainer>\n\ntype ClearableEntityManager = {\n clear?: () => void\n}\n\n/**\n * Builds a queue job handler that isolates every job in its own request\n * container, instead of sharing a single process-wide `EntityManager` fork\n * across all concurrent jobs.\n *\n * Under the async (BullMQ) strategy jobs run with real concurrency, so a\n * shared EM would interleave unit-of-work flushes between unrelated jobs and\n * never release its identity map. Creating one container per job removes both\n * the cross-job flush race and the unbounded identity-map growth, while\n * keeping the `ctx.resolve` contract and DI keys unchanged. See issue #2970.\n */\nexport function createPerJobWorkerHandler(\n workers: ModuleWorker[],\n createContainer: WorkerJobContainerFactory,\n): JobHandler {\n return async (job, ctx: JobContext) => {\n const container = await createContainer()\n try {\n for (const worker of workers) {\n await worker.handler(job, { ...ctx, resolve: container.resolve.bind(container) })\n }\n } finally {\n try {\n const em = container.resolve('em') as ClearableEntityManager | null\n em?.clear?.()\n } catch {\n // Best-effort: clearing the identity map is a memory optimization and\n // must never mask a job's own outcome.\n }\n }\n }\n}\n"],
|
|
5
|
+
"mappings": "AAwBO,SAAS,0BACd,SACA,iBACY;AACZ,SAAO,OAAO,KAAK,QAAoB;AACrC,UAAM,YAAY,MAAM,gBAAgB;AACxC,QAAI;AACF,iBAAW,UAAU,SAAS;AAC5B,cAAM,OAAO,QAAQ,KAAK,EAAE,GAAG,KAAK,SAAS,UAAU,QAAQ,KAAK,SAAS,EAAE,CAAC;AAAA,MAClF;AAAA,IACF,UAAE;AACA,UAAI;AACF,cAAM,KAAK,UAAU,QAAQ,IAAI;AACjC,YAAI,QAAQ;AAAA,MACd,QAAQ;AAAA,MAGR;AAAA,IACF;AAAA,EACF;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/mercato.js
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
resolveLazyRestart
|
|
11
11
|
} from "./lib/auto-spawn-workers.js";
|
|
12
12
|
import { startLazyWorkerSupervisor } from "./lib/queue-worker-supervisor.js";
|
|
13
|
+
import { createPerJobWorkerHandler } from "./lib/worker-job-handler.js";
|
|
13
14
|
import {
|
|
14
15
|
resolveAutoSpawnSchedulerMode,
|
|
15
16
|
resolveLazySchedulerPollMs,
|
|
@@ -25,6 +26,7 @@ import {
|
|
|
25
26
|
import { parseModuleInstallArgs } from "./lib/module-install-args.js";
|
|
26
27
|
import { resolveNextBuildIdCandidate } from "./lib/next-build-id.js";
|
|
27
28
|
import { acquireServerStartLock } from "./lib/server-start-lock.js";
|
|
29
|
+
import { assertSingleInstanceStrategies } from "./lib/single-instance-strategy-guard.js";
|
|
28
30
|
import { createDevEnvReloader, watchDevEnvFiles } from "./lib/dev-env-reload.js";
|
|
29
31
|
const lazyIntegration = () => import("./lib/testing/integration.js");
|
|
30
32
|
import path from "node:path";
|
|
@@ -1224,7 +1226,6 @@ async function run(argv = process.argv) {
|
|
|
1224
1226
|
return;
|
|
1225
1227
|
}
|
|
1226
1228
|
const { createRequestContainer } = await import("@open-mercato/shared/lib/di/container");
|
|
1227
|
-
const container = await createRequestContainer();
|
|
1228
1229
|
console.log(`[worker] Starting workers for all queues: ${discoveredQueues.join(", ")}`);
|
|
1229
1230
|
const workerPromises = discoveredQueues.map(async (queue) => {
|
|
1230
1231
|
const queueWorkers = allWorkers.filter((w) => w.queue === queue);
|
|
@@ -1236,11 +1237,7 @@ async function run(argv = process.argv) {
|
|
|
1236
1237
|
connection: queueRedisUrl ? { url: queueRedisUrl } : void 0,
|
|
1237
1238
|
concurrency,
|
|
1238
1239
|
background: true,
|
|
1239
|
-
handler:
|
|
1240
|
-
for (const worker of queueWorkers) {
|
|
1241
|
-
await worker.handler(job, { ...ctx, resolve: container.resolve.bind(container) });
|
|
1242
|
-
}
|
|
1243
|
-
}
|
|
1240
|
+
handler: createPerJobWorkerHandler(queueWorkers, createRequestContainer)
|
|
1244
1241
|
});
|
|
1245
1242
|
});
|
|
1246
1243
|
await Promise.all(workerPromises);
|
|
@@ -1251,7 +1248,6 @@ async function run(argv = process.argv) {
|
|
|
1251
1248
|
const queueWorkers = allWorkers.filter((w) => w.queue === queueName);
|
|
1252
1249
|
if (queueWorkers.length > 0) {
|
|
1253
1250
|
const { createRequestContainer } = await import("@open-mercato/shared/lib/di/container");
|
|
1254
|
-
const container = await createRequestContainer();
|
|
1255
1251
|
const concurrency = concurrencyOverride ?? Math.max(...queueWorkers.map((w) => w.concurrency), 1);
|
|
1256
1252
|
console.log(`[worker] Found ${queueWorkers.length} worker(s) for queue "${queueName}"`);
|
|
1257
1253
|
const queueRedisUrl = getRedisUrl("QUEUE");
|
|
@@ -1259,11 +1255,7 @@ async function run(argv = process.argv) {
|
|
|
1259
1255
|
queueName,
|
|
1260
1256
|
connection: queueRedisUrl ? { url: queueRedisUrl } : void 0,
|
|
1261
1257
|
concurrency,
|
|
1262
|
-
handler:
|
|
1263
|
-
for (const worker of queueWorkers) {
|
|
1264
|
-
await worker.handler(job, { ...ctx, resolve: container.resolve.bind(container) });
|
|
1265
|
-
}
|
|
1266
|
-
}
|
|
1258
|
+
handler: createPerJobWorkerHandler(queueWorkers, createRequestContainer)
|
|
1267
1259
|
});
|
|
1268
1260
|
} else {
|
|
1269
1261
|
console.error(`No workers found for queue "${queueName}"`);
|
|
@@ -1781,6 +1773,7 @@ async function run(argv = process.argv) {
|
|
|
1781
1773
|
const autoSpawnSchedulerMode = resolveAutoSpawnSchedulerMode(process.env);
|
|
1782
1774
|
const queueStrategy = process.env.QUEUE_STRATEGY || "local";
|
|
1783
1775
|
const runtimeEnv = buildServerProcessEnvironment(process.env);
|
|
1776
|
+
assertSingleInstanceStrategies(runtimeEnv);
|
|
1784
1777
|
const schedulerCommand = lookupModuleCommand(getCliModules(), "scheduler", "start");
|
|
1785
1778
|
const serverStartLock = acquireServerStartLock(appDir, {
|
|
1786
1779
|
port: runtimeEnv.PORT ?? process.env.PORT ?? null
|