instrumentation.ts
Rama main · réplica de lectura del repositorio original.
// instrumentation.ts — initialize the database runtime at server startup.
// Request-triggered maintenance is handled in lib/requestMaintenance.ts. Web Push also has
// a low-frequency unref'ed sweep so subscribed users receive day-based events while inactive;
// the timer does not keep an otherwise idle Node process alive. Database reconnects use an
// unref'ed backoff in lib/db.ts.
export async function register() {
if (process.env.NEXT_RUNTIME !== 'nodejs') return;
let flushOnExit: (() => void) | undefined;
try {
const db = await import('./lib/db');
flushOnExit = db.flushOnExit;
await db.initDB();
try {
const { ensureSetupBootstrapToken } = await import('./lib/setupBootstrap');
const boot = ensureSetupBootstrapToken();
if (boot) {
const expires = new Date(boot.expiresAt).toISOString();
const lines = boot.token
? ['[setup] 尚未初始化:請開啟 /setup 並輸入下列一次性初始化憑證(僅顯示一次,請妥善保存)', '[setup] token: ' + boot.token, '[setup] 到期時間: ' + expires]
: ['[setup] 尚未初始化:請開啟 /setup 並輸入環境變數 SETUP_BOOTSTRAP_TOKEN 設定的憑證', '[setup] 到期時間: ' + expires];
console.warn(lines.join('\n'));
}
} catch (error) {
console.error('[setup] bootstrap token initialisation failed', error instanceof Error ? error.message : 'unknown');
}
} catch (error) {
// Database availability is a runtime dependency, not a reason to make
// Next.js fail its instrumentation hook. lib/db.ts keeps retrying with an
// unref'ed backoff and publishes the adapter once migrations succeed.
const message = error instanceof Error ? error.message : String(error);
console.error(`[db] startup connection unavailable; retrying: ${message}`);
}
if (process.env.NEXT_RUNTIME === 'nodejs') {
void import('./lib/webPushEvents')
.then(({ startWebPushScheduler }) => startWebPushScheduler())
.catch((error) => console.error('[web-push] scheduler startup failed', error));
}
// 程序結束時保留既有關閉 hook;PostgreSQL 寫入已即時 commit。
if (flushOnExit) {
process.once('SIGINT', () => { flushOnExit?.(); process.exit(0); });
process.once('SIGTERM', () => { flushOnExit?.(); process.exit(0); });
}
}