@indigoai-us/hq-cloud 6.18.14-alpha.2 → 6.18.14
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/bin/sync-runner-receiver-unresolved-company.test.d.ts +2 -0
- package/dist/bin/sync-runner-receiver-unresolved-company.test.d.ts.map +1 -0
- package/dist/bin/sync-runner-receiver-unresolved-company.test.js +379 -0
- package/dist/bin/sync-runner-receiver-unresolved-company.test.js.map +1 -0
- package/dist/bin/sync-runner-watch-loop.d.ts +2 -1
- package/dist/bin/sync-runner-watch-loop.d.ts.map +1 -1
- package/dist/bin/sync-runner-watch-loop.js +76 -50
- package/dist/bin/sync-runner-watch-loop.js.map +1 -1
- package/dist/bin/sync-runner-watch-loop.test.js +2 -199
- package/dist/bin/sync-runner-watch-loop.test.js.map +1 -1
- package/dist/bin/sync-runner.d.ts +1 -12
- package/dist/bin/sync-runner.d.ts.map +1 -1
- package/dist/bin/sync-runner.js +14 -32
- package/dist/bin/sync-runner.js.map +1 -1
- package/dist/bin/sync-runner.test.js +4 -4
- package/dist/bin/sync-runner.test.js.map +1 -1
- package/dist/cli/sync.d.ts.map +1 -1
- package/dist/cli/sync.js +22 -18
- package/dist/cli/sync.js.map +1 -1
- package/dist/cli/sync.test.js +32 -44
- package/dist/cli/sync.test.js.map +1 -1
- package/dist/object-io.d.ts.map +1 -1
- package/dist/object-io.js +10 -0
- package/dist/object-io.js.map +1 -1
- package/dist/object-io.test.js +28 -1
- package/dist/object-io.test.js.map +1 -1
- package/dist/qmd-reindex.d.ts +10 -30
- package/dist/qmd-reindex.d.ts.map +1 -1
- package/dist/qmd-reindex.js +41 -148
- package/dist/qmd-reindex.js.map +1 -1
- package/dist/qmd-reindex.test.js +77 -110
- package/dist/qmd-reindex.test.js.map +1 -1
- package/dist/sync/push-receiver.d.ts +10 -14
- package/dist/sync/push-receiver.d.ts.map +1 -1
- package/dist/sync/push-receiver.js +40 -71
- package/dist/sync/push-receiver.js.map +1 -1
- package/dist/sync/push-receiver.test.js +1 -84
- package/dist/sync/push-receiver.test.js.map +1 -1
- package/dist/sync-core.d.ts +7 -0
- package/dist/sync-core.d.ts.map +1 -1
- package/dist/sync-core.js +12 -0
- package/dist/sync-core.js.map +1 -1
- package/package.json +1 -1
- package/dist/sync/targeted-pull-prefixes.d.ts +0 -9
- package/dist/sync/targeted-pull-prefixes.d.ts.map +0 -1
- package/dist/sync/targeted-pull-prefixes.js +0 -43
- package/dist/sync/targeted-pull-prefixes.js.map +0 -1
- package/dist/sync/targeted-pull-prefixes.test.d.ts +0 -2
- package/dist/sync/targeted-pull-prefixes.test.d.ts.map +0 -1
- package/dist/sync/targeted-pull-prefixes.test.js +0 -33
- package/dist/sync/targeted-pull-prefixes.test.js.map +0 -1
|
@@ -35,6 +35,7 @@ import { InlineSyncWorkerAdapter, } from "../sync/sync-work.js";
|
|
|
35
35
|
import { buildRoutePullArgv, buildScopedPushArgv, buildScopedDrainPullArgv, buildTargetedPullArgv, isWatchRouteSelected, routeChangeToTarget, routeKey, scopePathForRoute, } from "./sync-runner-watch-routes.js";
|
|
36
36
|
import { resolveSkipCompanies } from "./sync-runner-planning.js";
|
|
37
37
|
const FULL_RECONCILE_EVERY_TICKS = 10;
|
|
38
|
+
const warnedUnresolvedReceiverCompanies = new Set();
|
|
38
39
|
/** Maximum time shutdown waits for event-sync startup before abandoning it. */
|
|
39
40
|
export const EVENT_SYNC_STARTUP_SHUTDOWN_WAIT_MS = 5_000;
|
|
40
41
|
/** A deferred full chore must get the next admission after this long. */
|
|
@@ -1318,6 +1319,17 @@ function isBulkIntentOverride() {
|
|
|
1318
1319
|
function passExitCode(outcome) {
|
|
1319
1320
|
return typeof outcome === "number" ? outcome : outcome.exitCode;
|
|
1320
1321
|
}
|
|
1322
|
+
export function shouldAcknowledgeParallelUnresolvedCompany(accepted, exitCode) {
|
|
1323
|
+
return accepted && exitCode === UNRESOLVED_COMPANY_EXIT;
|
|
1324
|
+
}
|
|
1325
|
+
function unresolvedReceiverMessagesWereRedelivered(events, receiveCountsByPath) {
|
|
1326
|
+
return events.every((event) => {
|
|
1327
|
+
const receiveCounts = receiveCountsByPath?.get(event.relativePath);
|
|
1328
|
+
return receiveCounts !== undefined &&
|
|
1329
|
+
receiveCounts.length > 0 &&
|
|
1330
|
+
receiveCounts.every((count) => count !== undefined && Number.isFinite(count) && count >= 2);
|
|
1331
|
+
});
|
|
1332
|
+
}
|
|
1321
1333
|
function targetedReceiverDispatchError(outcome, accepted, authRequiredExitCode) {
|
|
1322
1334
|
const exitCode = passExitCode(outcome);
|
|
1323
1335
|
const result = typeof outcome === "number" ? undefined : outcome.result;
|
|
@@ -1376,18 +1388,8 @@ export async function runWatchLoop(argv, parsed, deps, runtime) {
|
|
|
1376
1388
|
((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
|
|
1377
1389
|
const stdout = deps.stdout ?? process.stdout;
|
|
1378
1390
|
const idleHeartbeatIntervalMs = deps.idleHeartbeatIntervalMs ?? WATCH_IDLE_HEARTBEAT_INTERVAL_MS;
|
|
1379
|
-
const writeMaintenanceProgress = () => {
|
|
1380
|
-
stdout.write(JSON.stringify({
|
|
1381
|
-
type: "maintenance-progress",
|
|
1382
|
-
company: "watch",
|
|
1383
|
-
bytesProcessed: 0,
|
|
1384
|
-
totalBytes: 0,
|
|
1385
|
-
}) + "\n");
|
|
1386
|
-
};
|
|
1387
1391
|
const monotonicNow = deps.monotonicNow ?? (() => performance.now());
|
|
1388
1392
|
const runPass = deps.runPass ?? runtime.runPassWithOperationLockAlreadyHeld;
|
|
1389
|
-
const qmdShutdownController = new AbortController();
|
|
1390
|
-
const runPassSupportsQmdLifecycle = deps.runPass === undefined || deps.runPassSupportsQmdLifecycle === true;
|
|
1391
1393
|
const runPassSupportsCooperativeCheckpoint = deps.runPass === undefined || deps.runPassSupportsCooperativeCheckpoint === true;
|
|
1392
1394
|
const pollIdx = argv.indexOf("--poll-remote-ms");
|
|
1393
1395
|
// An explicit --poll-remote-ms pins a fixed interval (menubar/CLI still set
|
|
@@ -1595,20 +1597,13 @@ export async function runWatchLoop(argv, parsed, deps, runtime) {
|
|
|
1595
1597
|
}
|
|
1596
1598
|
};
|
|
1597
1599
|
const invokePass = () => {
|
|
1598
|
-
if (!runPassSupportsCooperativeCheckpoint)
|
|
1599
|
-
|
|
1600
|
-
return runPass(passArgvForRun);
|
|
1601
|
-
return runPass(passArgvForRun, undefined, undefined, undefined, undefined, qmdShutdownController.signal, writeMaintenanceProgress, idleHeartbeatIntervalMs);
|
|
1602
|
-
}
|
|
1600
|
+
if (!runPassSupportsCooperativeCheckpoint)
|
|
1601
|
+
return runPass(passArgvForRun);
|
|
1603
1602
|
// This callback is emitted by the production runner after journal
|
|
1604
1603
|
// repair/seed and before fanout. It starts ingress early, but never
|
|
1605
1604
|
// admits a second durable writer: queued realtime still waits for the
|
|
1606
1605
|
// existing scheduler's cooperative hand-off checkpoint.
|
|
1607
|
-
|
|
1608
|
-
if (!runPassSupportsQmdLifecycle) {
|
|
1609
|
-
return runPass(passArgvForRun, checkpoint, onJournalsReady, recordDurableAppliedUpserts, workClass);
|
|
1610
|
-
}
|
|
1611
|
-
return runPass(passArgvForRun, checkpoint, onJournalsReady, recordDurableAppliedUpserts, workClass, qmdShutdownController.signal, writeMaintenanceProgress, idleHeartbeatIntervalMs);
|
|
1606
|
+
return runPass(passArgvForRun, checkpoint, () => activateEventPushSurfaces(), recordDurableAppliedUpserts, workClass);
|
|
1612
1607
|
};
|
|
1613
1608
|
// Observe the heap at pass boundaries — a gated checkpoint immediately before
|
|
1614
1609
|
// admitting a pass and immediately after it returns. A pass that runs a long
|
|
@@ -1801,14 +1796,18 @@ export async function runWatchLoop(argv, parsed, deps, runtime) {
|
|
|
1801
1796
|
resolveInterruptWait = null;
|
|
1802
1797
|
resolve?.();
|
|
1803
1798
|
};
|
|
1804
|
-
let reportWatcherLiveness = () => undefined;
|
|
1805
1799
|
const waitForNextPass = async (delayMs) => {
|
|
1806
1800
|
if (interruptGeneration !== observedInterruptGeneration) {
|
|
1807
1801
|
observedInterruptGeneration = interruptGeneration;
|
|
1808
1802
|
return;
|
|
1809
1803
|
}
|
|
1810
1804
|
const heartbeatTimer = setInterval(() => {
|
|
1811
|
-
|
|
1805
|
+
stdout.write(JSON.stringify({
|
|
1806
|
+
type: "maintenance-progress",
|
|
1807
|
+
company: "watch",
|
|
1808
|
+
bytesProcessed: 0,
|
|
1809
|
+
totalBytes: 0,
|
|
1810
|
+
}) + "\n");
|
|
1812
1811
|
reportWatcherLiveness();
|
|
1813
1812
|
}, idleHeartbeatIntervalMs);
|
|
1814
1813
|
heartbeatTimer.unref?.();
|
|
@@ -2109,7 +2108,7 @@ export async function runWatchLoop(argv, parsed, deps, runtime) {
|
|
|
2109
2108
|
* liveness heartbeat as well so an operator can distinguish a live watcher
|
|
2110
2109
|
* from a long-running poll-only process without inspecting /proc.
|
|
2111
2110
|
*/
|
|
2112
|
-
reportWatcherLiveness = () => {
|
|
2111
|
+
const reportWatcherLiveness = () => {
|
|
2113
2112
|
if (!eventPush || stopped)
|
|
2114
2113
|
return;
|
|
2115
2114
|
reattemptWatcherDiscoveryIfDue();
|
|
@@ -3308,6 +3307,18 @@ export async function runWatchLoop(argv, parsed, deps, runtime) {
|
|
|
3308
3307
|
};
|
|
3309
3308
|
let receiver = null;
|
|
3310
3309
|
let receiverHasQueuedWork = false;
|
|
3310
|
+
const warnUnresolvedReceiverCompany = (route, pathCount) => {
|
|
3311
|
+
if (route.kind !== "company" ||
|
|
3312
|
+
warnedUnresolvedReceiverCompanies.has(route.slug))
|
|
3313
|
+
return;
|
|
3314
|
+
warnedUnresolvedReceiverCompanies.add(route.slug);
|
|
3315
|
+
(deps.stderr ?? process.stderr).write(`${JSON.stringify({
|
|
3316
|
+
level: "warn",
|
|
3317
|
+
event: "receiver.unresolved-company",
|
|
3318
|
+
companySlug: route.slug,
|
|
3319
|
+
pathCount,
|
|
3320
|
+
})}\n`);
|
|
3321
|
+
};
|
|
3311
3322
|
const onReceiveActivity = (hasMessages) => {
|
|
3312
3323
|
receiverHasQueuedWork = hasMessages;
|
|
3313
3324
|
if (hasMessages)
|
|
@@ -3555,7 +3566,7 @@ export async function runWatchLoop(argv, parsed, deps, runtime) {
|
|
|
3555
3566
|
// a known-small event can be slow solely because an earlier event exhausted
|
|
3556
3567
|
// the delivery-wide fast budget.
|
|
3557
3568
|
const receiverLaneByBatch = new WeakMap();
|
|
3558
|
-
const drainParallelReceiverLane = async (lane, laneEvents) => {
|
|
3569
|
+
const drainParallelReceiverLane = async (lane, laneEvents, receiveCountsByPath) => {
|
|
3559
3570
|
const eventsByRoute = new Map();
|
|
3560
3571
|
for (const event of laneEvents) {
|
|
3561
3572
|
const route = routeChangeToTarget(event.relativePath);
|
|
@@ -3569,20 +3580,31 @@ export async function runWatchLoop(argv, parsed, deps, runtime) {
|
|
|
3569
3580
|
// Submit every route in this lane before awaiting any result. In
|
|
3570
3581
|
// particular, a later route's fast receipt must never wait for an
|
|
3571
3582
|
// earlier route's slow pull to finish.
|
|
3572
|
-
const
|
|
3583
|
+
const routeGroups = [...eventsByRoute.values()];
|
|
3584
|
+
const completed = await Promise.all(routeGroups.map(({ route, events }) => {
|
|
3573
3585
|
return runRealtimePass("receiver", "pull", events.map((event) => event.relativePath), lane, (slice, telemetry, coordinatorFenced) => {
|
|
3574
3586
|
const slicePaths = slice.paths.map((path) => path.canonicalPath);
|
|
3575
3587
|
const exactFileUpserts = exactUpsertPathsForCoordinatorSlice(events, slicePaths);
|
|
3576
3588
|
return withScopeContentHashesFile(route, events, slicePaths, (contentHashesFile) => runGuarded(buildTargetedPullArgv(route, passArgv, slicePaths, exactFileUpserts, contentHashesFile), undefined, lane, "realtime", lane === "fast", slice.signal, false, telemetry, coordinatorFenced));
|
|
3577
3589
|
});
|
|
3578
3590
|
}));
|
|
3579
|
-
for (const execution of completed) {
|
|
3580
|
-
|
|
3591
|
+
for (const [index, execution] of completed.entries()) {
|
|
3592
|
+
const { route, events } = routeGroups[index];
|
|
3593
|
+
const pathCount = events.length;
|
|
3594
|
+
const exitCode = passExitCode(execution.result);
|
|
3595
|
+
if (shouldAcknowledgeParallelUnresolvedCompany(execution.accepted, exitCode)) {
|
|
3596
|
+
if (!unresolvedReceiverMessagesWereRedelivered(events, receiveCountsByPath)) {
|
|
3597
|
+
throw targetedReceiverDispatchError(execution.result, execution.accepted, runtime.authRequiredPassExit);
|
|
3598
|
+
}
|
|
3599
|
+
warnUnresolvedReceiverCompany(route, pathCount);
|
|
3600
|
+
continue;
|
|
3601
|
+
}
|
|
3602
|
+
if (!execution.accepted || exitCode !== 0) {
|
|
3581
3603
|
throw targetedReceiverDispatchError(execution.result, execution.accepted, runtime.authRequiredPassExit);
|
|
3582
3604
|
}
|
|
3583
3605
|
}
|
|
3584
3606
|
};
|
|
3585
|
-
const receiverSyncBatchFn = async ({ events }) => {
|
|
3607
|
+
const receiverSyncBatchFn = async ({ events, approximateReceiveCountsByPath, }) => {
|
|
3586
3608
|
if (stopped)
|
|
3587
3609
|
return;
|
|
3588
3610
|
// The injectable receiver seam and the production SQS receiver both
|
|
@@ -3600,19 +3622,19 @@ export async function runWatchLoop(argv, parsed, deps, runtime) {
|
|
|
3600
3622
|
const lane = receiverLaneByBatch.get(events);
|
|
3601
3623
|
if (lane) {
|
|
3602
3624
|
receiverLaneByBatch.delete(events);
|
|
3603
|
-
await drainParallelReceiverLane(lane, events);
|
|
3625
|
+
await drainParallelReceiverLane(lane, events, approximateReceiveCountsByPath);
|
|
3604
3626
|
return;
|
|
3605
3627
|
}
|
|
3606
3628
|
// Direct embedders may invoke the engine without first going through
|
|
3607
3629
|
// SqsPushReceiver. Preserve that seam while applying the same
|
|
3608
3630
|
// delivery-wide partition the receiver would expose.
|
|
3609
3631
|
const lanes = partitionByKnownSizes(events, receiverEventSize);
|
|
3610
|
-
await drainParallelReceiverLane("fast", lanes.fast);
|
|
3611
|
-
await drainParallelReceiverLane("slow", lanes.slow);
|
|
3632
|
+
await drainParallelReceiverLane("fast", lanes.fast, approximateReceiveCountsByPath);
|
|
3633
|
+
await drainParallelReceiverLane("slow", lanes.slow, approximateReceiveCountsByPath);
|
|
3612
3634
|
return;
|
|
3613
3635
|
}
|
|
3614
3636
|
const lanes = partitionByKnownSizes(events, receiverEventSize);
|
|
3615
|
-
const drainLane = async (lane, laneEvents) => {
|
|
3637
|
+
const drainLane = async (lane, laneEvents, receiveCountsByPath) => {
|
|
3616
3638
|
const eventsByRoute = new Map();
|
|
3617
3639
|
for (const event of laneEvents) {
|
|
3618
3640
|
const route = routeChangeToTarget(event.relativePath);
|
|
@@ -3632,7 +3654,15 @@ export async function runWatchLoop(argv, parsed, deps, runtime) {
|
|
|
3632
3654
|
for (const { route, events: routeEvents, upsertPaths } of eventsByRoute.values()) {
|
|
3633
3655
|
const paths = routeEvents.map((event) => event.relativePath);
|
|
3634
3656
|
const result = await withScopeContentHashesFile(route, routeEvents, paths, (contentHashesFile) => runGuarded(buildTargetedPullArgv(route, passArgv, paths, upsertPaths, contentHashesFile), undefined, lane, "realtime"));
|
|
3635
|
-
|
|
3657
|
+
const exitCode = passExitCode(result);
|
|
3658
|
+
if (exitCode === UNRESOLVED_COMPANY_EXIT) {
|
|
3659
|
+
if (!unresolvedReceiverMessagesWereRedelivered(routeEvents, receiveCountsByPath)) {
|
|
3660
|
+
throw targetedReceiverDispatchError(result, true, runtime.authRequiredPassExit);
|
|
3661
|
+
}
|
|
3662
|
+
warnUnresolvedReceiverCompany(route, routeEvents.length);
|
|
3663
|
+
continue;
|
|
3664
|
+
}
|
|
3665
|
+
if (exitCode !== 0) {
|
|
3636
3666
|
throw targetedReceiverDispatchError(result, true, runtime.authRequiredPassExit);
|
|
3637
3667
|
}
|
|
3638
3668
|
}
|
|
@@ -3641,23 +3671,21 @@ export async function runWatchLoop(argv, parsed, deps, runtime) {
|
|
|
3641
3671
|
// established slow pass continue while the small scoped pull uses its
|
|
3642
3672
|
// ref-counted lock carve-out; the residue remains serialized and cannot
|
|
3643
3673
|
// starve the slow lane.
|
|
3644
|
-
await drainLane("fast", lanes.fast);
|
|
3645
|
-
await drainLane("slow", lanes.slow);
|
|
3674
|
+
await drainLane("fast", lanes.fast, approximateReceiveCountsByPath);
|
|
3675
|
+
await drainLane("slow", lanes.slow, approximateReceiveCountsByPath);
|
|
3646
3676
|
};
|
|
3647
|
-
receiverSyncBatchFn.partition = (events
|
|
3677
|
+
receiverSyncBatchFn.partition = (events) => {
|
|
3648
3678
|
const lanes = partitionByKnownSizes(events, receiverEventSize);
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
|
|
3655
|
-
|
|
3656
|
-
|
|
3657
|
-
|
|
3658
|
-
|
|
3659
|
-
return chunks;
|
|
3660
|
-
});
|
|
3679
|
+
if (parallelCoordinatorEnabled) {
|
|
3680
|
+
return ["fast", "slow"].flatMap((lane) => {
|
|
3681
|
+
const laneEvents = lanes[lane];
|
|
3682
|
+
if (laneEvents.length === 0)
|
|
3683
|
+
return [];
|
|
3684
|
+
receiverLaneByBatch.set(laneEvents, lane);
|
|
3685
|
+
return [laneEvents];
|
|
3686
|
+
});
|
|
3687
|
+
}
|
|
3688
|
+
return [lanes.fast, lanes.slow].filter((lane) => lane.length > 0);
|
|
3661
3689
|
};
|
|
3662
3690
|
const createReceiver = deps.createReceiver ?? (() => new NoopPushReceiver());
|
|
3663
3691
|
receiver = createReceiver({
|
|
@@ -3784,7 +3812,6 @@ export async function runWatchLoop(argv, parsed, deps, runtime) {
|
|
|
3784
3812
|
if (stopped)
|
|
3785
3813
|
return shutdownPromise ?? Promise.resolve();
|
|
3786
3814
|
stopped = true;
|
|
3787
|
-
qmdShutdownController.abort();
|
|
3788
3815
|
eventSyncShutdownDeadlineMs =
|
|
3789
3816
|
Date.now() + EVENT_SYNC_STARTUP_SHUTDOWN_WAIT_MS;
|
|
3790
3817
|
resolveStoppedQueue();
|
|
@@ -3977,7 +4004,6 @@ export async function runWatchLoop(argv, parsed, deps, runtime) {
|
|
|
3977
4004
|
if (recycleRequested !== null)
|
|
3978
4005
|
return;
|
|
3979
4006
|
recycleRequested = record;
|
|
3980
|
-
qmdShutdownController.abort();
|
|
3981
4007
|
// Additive, non-error NDJSON protocol event for the desktop supervisor.
|
|
3982
4008
|
stdout.write(`${JSON.stringify({ type: "heap-recycle", ...record })}\n`);
|
|
3983
4009
|
// Compact numeric line, worded to match none of hq-desktop-app's fatal
|