mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-31 04:12:10 +03:00
fix(sse): start credential-health sweep at boot so stale web sessions recover (#7689)
The credential-health scheduler (src/lib/credentialHealth/scheduler.ts) auto-inits on import, but nothing imported it at startup — only the on-demand credentialGate (open-sse/services/credentialGate.ts) does, lazily on the first gated request. So the boot-time sweep never ran, and web-session connections whose cookies expired overnight stayed red/unavailable until a real request re-tripped the failure (the "*-web providers go red on restart" complaint). Wire initCredentialHealthCheck() into src/instrumentation-node.ts (the real Next.js instrumentation startup) right after the runtime-settings restore, in its own try/catch with a [STARTUP] log line. Idempotent and self-disabling via OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK; cadence tunable via CREDENTIAL_HEALTH_CHECK_INTERVAL. The wiring MUST live in instrumentation-node.ts, NOT the unused src/server-init.ts — the latter never runs in production, which is why the earlier attempt (closed PR #7432) was a no-op. Test: tests/unit/credential-health-boot-wiring.test.ts asserts the boot wiring is present in instrumentation-node.ts and absent from the dead server-init.ts. Co-authored-by: Diego Rodrigues de Sa e Souza <diegosouza.pw@gmail.com>
This commit is contained in:
@@ -379,6 +379,22 @@ export async function registerNodejs(): Promise<void> {
|
||||
console.warn("[STARTUP] Could not restore runtime settings:", msg);
|
||||
}
|
||||
|
||||
// Proactively start the credential-health sweep at boot so stale web-session
|
||||
// connections (cookies that expired overnight) get re-probed and recovered on
|
||||
// startup — instead of staying red until the first real request lazily imports
|
||||
// the on-demand credentialGate. Idempotent; self-disables via
|
||||
// OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK and its cadence is tunable via
|
||||
// CREDENTIAL_HEALTH_CHECK_INTERVAL. NOTE: this MUST live here (the real Next.js
|
||||
// instrumentation startup), NOT in the unused src/server-init.ts.
|
||||
try {
|
||||
const { initCredentialHealthCheck } = await import("@/lib/credentialHealth/scheduler");
|
||||
initCredentialHealthCheck();
|
||||
console.log("[STARTUP] Credential health scheduler started");
|
||||
} catch (err: unknown) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
console.warn("[STARTUP] Could not start credential health scheduler:", msg);
|
||||
}
|
||||
|
||||
try {
|
||||
const { initAuditLog, cleanupExpiredLogs } = await import("@/lib/compliance/index");
|
||||
initAuditLog();
|
||||
|
||||
45
tests/unit/credential-health-boot-wiring.test.ts
Normal file
45
tests/unit/credential-health-boot-wiring.test.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { readFileSync, existsSync } from "node:fs";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
// The credential-health sweep re-probes web-session connections and recovers ones
|
||||
// whose cookies expired (the "*-web providers go red on restart" bug). scheduler.ts
|
||||
// only auto-inits when something imports it; nothing did at boot, so the sweep never
|
||||
// ran proactively at startup. This guards that the wiring lives in the REAL startup
|
||||
// (src/instrumentation-node.ts) and NOT in the unused src/server-init.ts — the exact
|
||||
// mistake that made the earlier attempt (closed PR #7432) a no-op.
|
||||
|
||||
const read = (rel: string) =>
|
||||
readFileSync(fileURLToPath(new URL(rel, import.meta.url)), "utf8");
|
||||
|
||||
const instrumentation = read("../../src/instrumentation-node.ts");
|
||||
|
||||
test("credential health scheduler is started from the real Next.js instrumentation startup", () => {
|
||||
assert.match(
|
||||
instrumentation,
|
||||
/import\(["']@\/lib\/credentialHealth\/scheduler["']\)/,
|
||||
"instrumentation-node.ts must import the scheduler at boot"
|
||||
);
|
||||
assert.match(
|
||||
instrumentation,
|
||||
/initCredentialHealthCheck\(\)/,
|
||||
"instrumentation-node.ts must call initCredentialHealthCheck() at boot"
|
||||
);
|
||||
assert.match(
|
||||
instrumentation,
|
||||
/\[STARTUP\] Credential health scheduler started/,
|
||||
"a [STARTUP] log line proves the boot wiring ran (grep-able in app.log)"
|
||||
);
|
||||
});
|
||||
|
||||
test("the wiring is NOT placed in the dead src/server-init.ts (the #7432 no-op)", () => {
|
||||
const url = new URL("../../src/server-init.ts", import.meta.url);
|
||||
const p = fileURLToPath(url);
|
||||
if (!existsSync(p)) return; // file removed upstream → nothing to guard
|
||||
assert.doesNotMatch(
|
||||
readFileSync(p, "utf8"),
|
||||
/initCredentialHealthCheck/,
|
||||
"server-init.ts is unused in production; wiring there never runs"
|
||||
);
|
||||
});
|
||||
Reference in New Issue
Block a user