/** * Data Sync Service - Sync raw MongoDB data to PostgreSQL master records */ // Framework imports import { Hono } from 'hono'; import { cors } from 'hono/cors'; // Library imports import { initializeServiceConfig } from '@stock-bot/config'; import { getLogger, setLoggerConfig, shutdownLoggers } from '@stock-bot/logger'; import { createAndConnectMongoDBClient, MongoDBClient } from '@stock-bot/mongodb-client'; import { createAndConnectPostgreSQLClient, PostgreSQLClient } from '@stock-bot/postgres-client'; import { Shutdown } from '@stock-bot/shutdown'; import { enhancedSyncManager } from './services/enhanced-sync-manager'; import { syncManager } from './services/sync-manager'; // Local imports import { setMongoDBClient, setPostgreSQLClient } from './clients'; import { enhancedSyncRoutes, healthRoutes, statsRoutes, syncRoutes } from './routes'; // Initialize configuration with automatic monorepo config inheritance const config = await initializeServiceConfig(); const serviceConfig = config.service; const databaseConfig = config.database; // Initialize logger with config const loggingConfig = config.logging; if (loggingConfig) { setLoggerConfig({ logLevel: loggingConfig.level, logConsole: true, logFile: false, environment: config.environment, }); } const app = new Hono(); // Add CORS middleware app.use( '*', cors({ origin: '*', allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], allowHeaders: ['Content-Type', 'Authorization'], credentials: false, }) ); const logger = getLogger('data-sync-service'); const PORT = serviceConfig.port; let server: ReturnType | null = null; let postgresClient: PostgreSQLClient | null = null; let mongoClient: MongoDBClient | null = null; // Initialize shutdown manager const shutdown = Shutdown.getInstance({ timeout: 15000 }); // Mount routes app.route('/health', healthRoutes); app.route('/sync', syncRoutes); app.route('/sync', enhancedSyncRoutes); app.route('/sync/stats', statsRoutes); // Initialize services async function initializeServices() { logger.info('Initializing data sync service...'); try { // Initialize MongoDB client logger.debug('Connecting to MongoDB...'); const mongoConfig = databaseConfig.mongodb; mongoClient = await createAndConnectMongoDBClient({ uri: mongoConfig.uri, database: mongoConfig.database, host: mongoConfig.host || 'localhost', port: mongoConfig.port || 27017, timeouts: { connectTimeout: 30000, socketTimeout: 30000, serverSelectionTimeout: 5000, }, }); setMongoDBClient(mongoClient); logger.info('MongoDB connected'); // Initialize PostgreSQL client logger.debug('Connecting to PostgreSQL...'); const pgConfig = databaseConfig.postgres; postgresClient = await createAndConnectPostgreSQLClient({ host: pgConfig.host, port: pgConfig.port, database: pgConfig.database, username: pgConfig.user, password: pgConfig.password, poolSettings: { min: 2, max: pgConfig.poolSize || 10, idleTimeoutMillis: pgConfig.idleTimeout || 30000, }, }); setPostgreSQLClient(postgresClient); logger.info('PostgreSQL connected'); // Initialize sync managers logger.debug('Initializing sync managers...'); await syncManager.initialize(); await enhancedSyncManager.initialize(); logger.info('Sync managers initialized'); logger.info('All services initialized successfully'); } catch (error) { logger.error('Failed to initialize services', { error }); throw error; } } // Start server async function startServer() { await initializeServices(); server = Bun.serve({ port: PORT, fetch: app.fetch, development: config.environment === 'development', }); logger.info(`Data Sync Service started on port ${PORT}`); } // Register shutdown handlers shutdown.onShutdown(async () => { if (server) { logger.info('Stopping HTTP server...'); try { server.stop(); logger.info('HTTP server stopped'); } catch (error) { logger.error('Error stopping HTTP server', { error }); } } }); shutdown.onShutdown(async () => { logger.info('Shutting down sync managers...'); try { await syncManager.shutdown(); await enhancedSyncManager.shutdown(); logger.info('Sync managers shut down'); } catch (error) { logger.error('Error shutting down sync managers', { error }); } }); shutdown.onShutdown(async () => { logger.info('Disconnecting from databases...'); try { if (mongoClient) { await mongoClient.disconnect(); } if (postgresClient) { await postgresClient.disconnect(); } logger.info('Database connections closed'); } catch (error) { logger.error('Error closing database connections', { error }); } }); shutdown.onShutdown(async () => { try { await shutdownLoggers(); // process.stdout.write('Data sync service loggers shut down\n'); } catch (error) { process.stderr.write(`Error shutting down loggers: ${error}\n`); } }); // Start the service startServer().catch(error => { logger.fatal('Failed to start data sync service', { error }); process.exit(1); }); logger.info('Data sync service startup initiated');