/** * Server start hook — Next runs register() once per server process, before * it serves the first request (a root instrumentation.ts is picked up with no * config in Next 15+). * * It boots the trading background work eagerly. getClients() in lib/clients.ts * starts the broker clients, the contract resolver, the reporter, the master * link, the client supervisor and the persisted-schedule resume — and it used * to run only on the first HTTP request. So a restarted instance (a crash, an * update, pm2 after a reboot) sat idle, not trading and invisible to the * master, until someone opened the dashboard or start-all's warm-up curl * happened to reach it. * * The boot must never take the server down with it: a failure is logged, and * if the boot never got going the first request still starts it through the * same lazy getClients() path as before. * * This module is its own server bundle, so it can hold its own instances of * lib/ modules, separate from the route handlers'. Anything the two must share * (the client pool, the scheduler, timers) lives on globalThis for that reason. */ export async function register(): Promise { // The nodejs check is the documented shape for a Node-only import, kept // exactly: the edge compile (Turbopack always builds one) inlines // NEXT_RUNTIME and drops the block, so lib/clients — sqlite, sockets — // never reaches the edge bundle, where it would fail the build. The build // check is defense in depth (Next itself doesn't call register() during // `next build`) — a build must never dial brokers or resume the scheduler. if (process.env.NEXT_RUNTIME === 'nodejs') { if (process.env.NEXT_PHASE === 'phase-production-build') return; try { const { getClients } = await import('./lib/clients'); getClients(); } catch (err) { const message = err instanceof Error ? err.message : String(err); console.error(`[instrumentation] eager boot failed — clients will start on the first request: ${message}`); } } }