import { createApp } from './app.js'; import { createEditQueue } from './queue/edit-queue.js'; import { processEditJob } from './queue/process-edit-job.js'; import { openDb, closeDb, pruneExpiredProposals, pruneIdempotencyKeys } from './db.js'; import { logger } from './logger.js'; import { initLiveReload } from './live-reload.js'; const PORT = parseInt(process.env.ORCHESTRATOR_PORT || '3001', 10); export async function startServer() { // Initialize database openDb(); logger.info({ event: 'db.opened' }, 'SQLite database opened'); // Create queue and wire consumer const queue = createEditQueue(); queue.startConsumer(processEditJob); // Periodic cleanup const cleanupInterval = setInterval(() => { pruneExpiredProposals(); pruneIdempotencyKeys(); }, 60_000); // Create and start HTTP server const app = createApp({ queue }); const server = app.listen(PORT, () => { logger.info({ event: 'server.started', port: PORT }, `Orchestrator listening on port ${PORT}`); }); // Optional websocket for browser reload on content writes initLiveReload(server); // Graceful shutdown let shuttingDown = false; async function shutdown(signal: string) { if (shuttingDown) return; shuttingDown = true; logger.info({ event: 'server.shutdown', signal }, `Received ${signal}, shutting down...`); clearInterval(cleanupInterval); // Stop accepting new connections server.close(() => { logger.info({ event: 'server.closed' }, 'HTTP server closed'); }); // Drain queue (finish current job) await queue.shutdown(); // Close database closeDb(); logger.info({ event: 'db.closed' }, 'Database closed'); process.exit(0); } process.on('SIGTERM', () => shutdown('SIGTERM')); process.on('SIGINT', () => shutdown('SIGINT')); } startServer().catch(err => { logger.fatal({ error: (err as Error).message }, 'Failed to start server'); process.exit(1); });