From d71fb28d60072aa569aad668cee62d7aec1db7e2 Mon Sep 17 00:00:00 2001 From: Brent Rager Date: Tue, 2 Jun 2026 18:07:06 -0400 Subject: [PATCH 1/2] SMOODEV-1527: Fix eso-refresher keep-alive (don't unref the interval) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The refresher exited 0 right after its initial mint+write — it unref'd the interval timer, and the 'await new Promise(() => {})' keep-alive in main() does NOT hold Node's event loop open on its own. Result: the sidecar CrashLoopBackOff'd (re-minting on each restart, which masked it, but it's not a stable daemon). Don't unref the production interval — it's what keeps the loop alive. Tests inject their own scheduler, so they're unaffected. Co-Authored-By: Claude Opus 4.8 (1M context) --- .changeset/eso-refresher-keepalive.md | 5 +++++ src/eso-refresher/index.ts | 8 ++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 .changeset/eso-refresher-keepalive.md diff --git a/.changeset/eso-refresher-keepalive.md b/.changeset/eso-refresher-keepalive.md new file mode 100644 index 0000000..8cbca4e --- /dev/null +++ b/.changeset/eso-refresher-keepalive.md @@ -0,0 +1,5 @@ +--- +'@smooai/config': patch +--- + +SMOODEV-1527: Fix the eso-refresher exiting immediately after its initial mint (it `unref()`'d the interval timer, and a pending `await new Promise(() => {})` doesn't hold Node's event loop open — so the process exited 0 → CrashLoopBackOff). The production interval now keeps the daemon alive; tests inject their own scheduler so they're unaffected. diff --git a/src/eso-refresher/index.ts b/src/eso-refresher/index.ts index 47e26e3..62e80d7 100644 --- a/src/eso-refresher/index.ts +++ b/src/eso-refresher/index.ts @@ -147,8 +147,12 @@ export interface EsoRefresherHandle { function defaultScheduler(fn: () => void, ms: number): { clear: () => void } { const t = setInterval(fn, ms); - // Don't keep the event loop alive solely for the timer in tests/CLI teardown. - if (typeof t.unref === 'function') t.unref(); + // SMOODEV-1527: do NOT unref() — the interval is what keeps the daemon's + // event loop alive. A pending `await new Promise(() => {})` in main() does + // NOT hold the loop open by itself, so unref'ing here let the process exit 0 + // right after the initial mint → CrashLoopBackOff. Tests inject their own + // scheduler, so this only affects the real CLI/sidecar (where we WANT it + // to keep running). `stop()` still calls clear() for clean shutdown. return { clear: () => clearInterval(t) }; } From 33663ae904b4a65a83be277715aa3b07f75ded77 Mon Sep 17 00:00:00 2001 From: Brent Rager Date: Wed, 8 Jul 2026 17:52:19 -0400 Subject: [PATCH 2/2] SMOODEV-1527: fix stale keep-alive comment at the main() hold point Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01LE7V35vzRiHyxBFE8wAxb4 --- src/eso-refresher/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/eso-refresher/index.ts b/src/eso-refresher/index.ts index 62e80d7..a56bbec 100644 --- a/src/eso-refresher/index.ts +++ b/src/eso-refresher/index.ts @@ -249,6 +249,7 @@ export async function main(): Promise { process.on('SIGTERM', () => shutdown('SIGTERM')); process.on('SIGINT', () => shutdown('SIGINT')); - // Keep alive — the interval timer is unref'd, so hold the loop open explicitly. + // The ref'd interval (SMOODEV-1527) is what actually holds the event loop + // open; this pending promise only keeps main() from returning. await new Promise(() => {}); }