@open-mercato/cli 0.6.4-develop.3949.1.adc3d0b3b1 → 0.6.4-develop.3962.1.70f30e284c
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/mercato.js +150 -95
- package/dist/mercato.js.map +2 -2
- package/package.json +5 -5
- package/src/__tests__/mercato.test.ts +12 -3
- package/src/lib/__tests__/dev-env-reload.test.ts +4 -2
- package/src/mercato.ts +124 -52
package/dist/mercato.js
CHANGED
|
@@ -322,6 +322,26 @@ function writeDevSplashRuntimeReady(reason) {
|
|
|
322
322
|
activity: reason ? `Restart completed after ${reason}` : "App runtime is ready"
|
|
323
323
|
});
|
|
324
324
|
}
|
|
325
|
+
function resolveDevWarmupReadyTimeoutMs(environment = process.env) {
|
|
326
|
+
const parsed = Number.parseInt(environment.OM_DEV_WARMUP_READY_TIMEOUT_MS ?? "", 10);
|
|
327
|
+
if (Number.isFinite(parsed) && parsed >= 0) return parsed;
|
|
328
|
+
return 3e5;
|
|
329
|
+
}
|
|
330
|
+
async function waitForDevWarmupReadyFile(filePath, options = {}) {
|
|
331
|
+
const normalized = filePath?.trim();
|
|
332
|
+
if (!normalized) return "ready";
|
|
333
|
+
const timeoutMs = options.timeoutMs ?? resolveDevWarmupReadyTimeoutMs();
|
|
334
|
+
const startedAt = Date.now();
|
|
335
|
+
while (true) {
|
|
336
|
+
if (options.signal?.aborted) return "aborted";
|
|
337
|
+
try {
|
|
338
|
+
if (fs.existsSync(normalized)) return "ready";
|
|
339
|
+
} catch {
|
|
340
|
+
}
|
|
341
|
+
if (timeoutMs >= 0 && Date.now() - startedAt >= timeoutMs) return "timeout";
|
|
342
|
+
await new Promise((resolve) => setTimeout(resolve, 250));
|
|
343
|
+
}
|
|
344
|
+
}
|
|
325
345
|
function waitForManagedProcessExit(proc, label) {
|
|
326
346
|
return new Promise((resolve) => {
|
|
327
347
|
proc.on("exit", (code, signal) => {
|
|
@@ -1551,55 +1571,65 @@ async function run(argv = process.argv) {
|
|
|
1551
1571
|
const waitForDevRestart = () => new Promise((resolve) => {
|
|
1552
1572
|
devRestartPromiseResolve = resolve;
|
|
1553
1573
|
});
|
|
1554
|
-
const startNextDev = (runtimeEnv) =>
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
const nextProcess = spawn("node", [nextBin, "dev", "--turbopack"], {
|
|
1559
|
-
stdio: ["inherit", "pipe", "pipe"],
|
|
1560
|
-
env: runtimeEnv,
|
|
1561
|
-
cwd: appDir
|
|
1574
|
+
const startNextDev = (runtimeEnv) => {
|
|
1575
|
+
let readyResolve = () => void 0;
|
|
1576
|
+
const readyPromise = new Promise((resolve) => {
|
|
1577
|
+
readyResolve = resolve;
|
|
1562
1578
|
});
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1579
|
+
const exitPromise = new Promise((resolve) => {
|
|
1580
|
+
writeDevSplashRuntimeStarting(
|
|
1581
|
+
lastRestartReason ? `Restarting Next.js dev server. Reason: ${lastRestartReason}` : "Starting Next.js dev server"
|
|
1582
|
+
);
|
|
1583
|
+
const nextProcess = spawn("node", [nextBin, "dev", "--turbopack"], {
|
|
1584
|
+
stdio: ["inherit", "pipe", "pipe"],
|
|
1585
|
+
env: runtimeEnv,
|
|
1586
|
+
cwd: appDir
|
|
1587
|
+
});
|
|
1588
|
+
processes.push(nextProcess);
|
|
1589
|
+
let combinedOutput = "";
|
|
1590
|
+
let reportedReady = false;
|
|
1591
|
+
const appendOutput = (chunk) => {
|
|
1592
|
+
combinedOutput += chunk;
|
|
1593
|
+
if (combinedOutput.length > 32768) {
|
|
1594
|
+
combinedOutput = combinedOutput.slice(-32768);
|
|
1595
|
+
}
|
|
1596
|
+
if (!reportedReady && /\bready in\b/i.test(chunk)) {
|
|
1597
|
+
reportedReady = true;
|
|
1598
|
+
writeDevSplashRuntimeReady(lastRestartReason ?? void 0);
|
|
1599
|
+
lastRestartReason = null;
|
|
1600
|
+
readyResolve();
|
|
1601
|
+
}
|
|
1602
|
+
};
|
|
1603
|
+
nextProcess.stdout?.on("data", (chunk) => {
|
|
1604
|
+
const text = typeof chunk === "string" ? chunk : chunk.toString();
|
|
1605
|
+
process.stdout.write(text);
|
|
1606
|
+
appendOutput(text);
|
|
1607
|
+
});
|
|
1608
|
+
nextProcess.stderr?.on("data", (chunk) => {
|
|
1609
|
+
const text = typeof chunk === "string" ? chunk : chunk.toString();
|
|
1610
|
+
process.stderr.write(text);
|
|
1611
|
+
appendOutput(text);
|
|
1612
|
+
});
|
|
1613
|
+
nextProcess.on("exit", async (code, signal) => {
|
|
1614
|
+
if (!didRetryCorruptedTurbopackCache && isTurbopackCacheCorruption(combinedOutput)) {
|
|
1615
|
+
didRetryCorruptedTurbopackCache = true;
|
|
1616
|
+
lastRestartReason = "corrupted Turbopack dev cache";
|
|
1617
|
+
writeDevSplashRuntimeRestarting(lastRestartReason);
|
|
1618
|
+
console.log("[server] Detected corrupted Turbopack dev cache. Clearing .mercato/next/dev and restarting Next.js once...");
|
|
1619
|
+
removeTurbopackDevCache(appDir);
|
|
1620
|
+
const restarted = startNextDev(runtimeEnv);
|
|
1621
|
+
restarted.readyPromise.then(readyResolve);
|
|
1622
|
+
return resolve(await restarted.exitPromise);
|
|
1623
|
+
}
|
|
1624
|
+
resolve({
|
|
1625
|
+
label: "Next.js dev server",
|
|
1626
|
+
code,
|
|
1627
|
+
signal
|
|
1628
|
+
});
|
|
1600
1629
|
});
|
|
1601
1630
|
});
|
|
1602
|
-
|
|
1631
|
+
return { exitPromise, readyPromise };
|
|
1632
|
+
};
|
|
1603
1633
|
try {
|
|
1604
1634
|
while (!stopping) {
|
|
1605
1635
|
envReloader.reload();
|
|
@@ -1608,59 +1638,84 @@ async function run(argv = process.argv) {
|
|
|
1608
1638
|
const autoSpawnSchedulerMode = resolveAutoSpawnSchedulerMode(process.env);
|
|
1609
1639
|
const queueStrategy = process.env.QUEUE_STRATEGY || "local";
|
|
1610
1640
|
const schedulerCommand = lookupModuleCommand(getCliModules(), "scheduler", "start");
|
|
1641
|
+
const nextRuntime = startNextDev(runtimeEnv);
|
|
1642
|
+
const restartPromise = waitForDevRestart();
|
|
1643
|
+
const backgroundStartAbort = new AbortController();
|
|
1644
|
+
const cancelBackgroundStart = () => backgroundStartAbort.abort();
|
|
1645
|
+
nextRuntime.exitPromise.finally(cancelBackgroundStart);
|
|
1646
|
+
restartPromise.then(cancelBackgroundStart);
|
|
1647
|
+
let backgroundExitResolve = () => void 0;
|
|
1648
|
+
const backgroundExitPromise = new Promise((resolve) => {
|
|
1649
|
+
backgroundExitResolve = resolve;
|
|
1650
|
+
});
|
|
1611
1651
|
const managedExitPromises = [
|
|
1612
|
-
|
|
1613
|
-
|
|
1652
|
+
nextRuntime.exitPromise,
|
|
1653
|
+
restartPromise,
|
|
1654
|
+
backgroundExitPromise
|
|
1614
1655
|
];
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
const
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
}
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
appDir,
|
|
1625
|
-
runtimeEnv,
|
|
1626
|
-
workers: discoveredWorkers,
|
|
1627
|
-
pollMs: resolveLazyPollMs(process.env),
|
|
1628
|
-
restartOnUnexpectedExit: resolveLazyRestart(process.env)
|
|
1629
|
-
});
|
|
1630
|
-
} else {
|
|
1631
|
-
console.log("[server] Eager worker auto-spawn enabled - starting workers for all queues...");
|
|
1632
|
-
const workerProcess = spawn("node", [mercatoBin, "queue", "worker", "--all"], {
|
|
1633
|
-
stdio: "inherit",
|
|
1634
|
-
env: runtimeEnv,
|
|
1635
|
-
cwd: appDir
|
|
1636
|
-
});
|
|
1637
|
-
processes.push(workerProcess);
|
|
1638
|
-
managedExitPromises.push(waitForManagedProcessExit(workerProcess, formatQueueWorkerLabel(discoveredWorkerQueues)));
|
|
1656
|
+
const startBackgroundServices = async () => {
|
|
1657
|
+
if (stopping || backgroundStartAbort.signal.aborted) return;
|
|
1658
|
+
const warmupReady = await waitForDevWarmupReadyFile(process.env.OM_DEV_WARMUP_READY_FILE, {
|
|
1659
|
+
timeoutMs: resolveDevWarmupReadyTimeoutMs(process.env),
|
|
1660
|
+
signal: backgroundStartAbort.signal
|
|
1661
|
+
});
|
|
1662
|
+
if (warmupReady === "aborted" || stopping || backgroundStartAbort.signal.aborted) return;
|
|
1663
|
+
if (warmupReady === "timeout") {
|
|
1664
|
+
console.warn("[server] Timed out waiting for dev warmup marker; starting background services anyway.");
|
|
1639
1665
|
}
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1666
|
+
if (autoSpawnWorkersMode !== "off") {
|
|
1667
|
+
const discoveredWorkers = getRegisteredCliWorkers();
|
|
1668
|
+
const discoveredWorkerQueues = [...new Set(discoveredWorkers.map((worker) => worker.queue))];
|
|
1669
|
+
if (discoveredWorkerQueues.length === 0) {
|
|
1670
|
+
console.error("[server] AUTO_SPAWN_WORKERS is enabled, but no queues were discovered from CLI modules. Run `yarn generate` and verify `.mercato/generated/modules.cli.generated.ts` contains worker entries. Continuing without auto-spawned workers.");
|
|
1671
|
+
} else if (autoSpawnWorkersMode === "lazy") {
|
|
1672
|
+
console.log(`[server] Lazy worker auto-spawn enabled \u2014 workers will start on first job (${discoveredWorkerQueues.length} queue(s) watched).`);
|
|
1673
|
+
activeLazySupervisor = startLazyWorkerSupervisor({
|
|
1674
|
+
mercatoBin,
|
|
1675
|
+
appDir,
|
|
1676
|
+
runtimeEnv,
|
|
1677
|
+
workers: discoveredWorkers,
|
|
1678
|
+
pollMs: resolveLazyPollMs(process.env),
|
|
1679
|
+
restartOnUnexpectedExit: resolveLazyRestart(process.env)
|
|
1680
|
+
});
|
|
1681
|
+
} else {
|
|
1682
|
+
console.log("[server] Eager worker auto-spawn enabled - starting workers for all queues...");
|
|
1683
|
+
const workerProcess = spawn("node", [mercatoBin, "queue", "worker", "--all"], {
|
|
1684
|
+
stdio: "inherit",
|
|
1685
|
+
env: runtimeEnv,
|
|
1686
|
+
cwd: appDir
|
|
1687
|
+
});
|
|
1688
|
+
processes.push(workerProcess);
|
|
1689
|
+
waitForManagedProcessExit(workerProcess, formatQueueWorkerLabel(discoveredWorkerQueues)).then(backgroundExitResolve);
|
|
1690
|
+
}
|
|
1662
1691
|
}
|
|
1663
|
-
|
|
1692
|
+
if (autoSpawnSchedulerMode !== "off" && queueStrategy === "local") {
|
|
1693
|
+
if (schedulerCommand.status !== "ok") {
|
|
1694
|
+
console.log(`[server] Skipping scheduler auto-start \u2014 ${describeMissingModuleCommand(schedulerCommand)}`);
|
|
1695
|
+
} else if (autoSpawnSchedulerMode === "lazy") {
|
|
1696
|
+
console.log("[server] Lazy scheduler auto-spawn enabled - scheduler will start when an enabled schedule exists.");
|
|
1697
|
+
activeLazySchedulerSupervisor = startLazySchedulerSupervisor({
|
|
1698
|
+
mercatoBin,
|
|
1699
|
+
appDir,
|
|
1700
|
+
runtimeEnv,
|
|
1701
|
+
pollMs: resolveLazySchedulerPollMs(process.env),
|
|
1702
|
+
restartOnUnexpectedExit: resolveLazySchedulerRestart(process.env)
|
|
1703
|
+
});
|
|
1704
|
+
} else {
|
|
1705
|
+
console.log("[server] Eager scheduler auto-spawn enabled - starting scheduler polling engine...");
|
|
1706
|
+
const schedulerProcess = spawn("node", [mercatoBin, "scheduler", "start"], {
|
|
1707
|
+
stdio: "inherit",
|
|
1708
|
+
env: runtimeEnv,
|
|
1709
|
+
cwd: appDir
|
|
1710
|
+
});
|
|
1711
|
+
processes.push(schedulerProcess);
|
|
1712
|
+
waitForManagedProcessExit(schedulerProcess, "Scheduler polling engine").then(backgroundExitResolve);
|
|
1713
|
+
}
|
|
1714
|
+
}
|
|
1715
|
+
};
|
|
1716
|
+
nextRuntime.readyPromise.then(() => {
|
|
1717
|
+
void startBackgroundServices();
|
|
1718
|
+
});
|
|
1664
1719
|
if (generateWatcherMode === "in-process") {
|
|
1665
1720
|
console.log("[server] In-process generate watcher enabled \u2014 structural changes will regenerate without a sidecar process.");
|
|
1666
1721
|
activeGenerateWatcher = startInProcessGenerateWatcher({
|