stock-bot/apps/data-sync-service/src/index.ts
2025-06-20 16:53:30 -04:00

184 lines
5.2 KiB
TypeScript

/**
* 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<typeof Bun.serve> | 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');