Files
dynamic-sites-simple/server/src/index.ts
2026-04-23 08:04:34 -05:00

66 lines
1.9 KiB
TypeScript

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);
});