refactored data-sync service
This commit is contained in:
parent
1bb6b62408
commit
68d977f9e0
6 changed files with 183 additions and 134 deletions
|
|
@ -1,16 +1,23 @@
|
||||||
/**
|
/**
|
||||||
* Data Sync Service - Sync raw MongoDB data to PostgreSQL master records
|
* Data Sync Service - Sync raw MongoDB data to PostgreSQL master records
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Framework imports
|
||||||
import { Hono } from 'hono';
|
import { Hono } from 'hono';
|
||||||
import { cors } from 'hono/cors';
|
import { cors } from 'hono/cors';
|
||||||
|
|
||||||
|
// Library imports
|
||||||
import { initializeServiceConfig } from '@stock-bot/config-new';
|
import { initializeServiceConfig } from '@stock-bot/config-new';
|
||||||
import { getLogger, setLoggerConfig, shutdownLoggers } from '@stock-bot/logger';
|
import { getLogger, setLoggerConfig, shutdownLoggers } from '@stock-bot/logger';
|
||||||
import { createAndConnectMongoDBClient, MongoDBClient } from '@stock-bot/mongodb-client';
|
import { createAndConnectMongoDBClient, MongoDBClient } from '@stock-bot/mongodb-client';
|
||||||
import { createAndConnectPostgreSQLClient, PostgreSQLClient } from '@stock-bot/postgres-client';
|
import { createAndConnectPostgreSQLClient, PostgreSQLClient } from '@stock-bot/postgres-client';
|
||||||
import { Shutdown } from '@stock-bot/shutdown';
|
import { Shutdown } from '@stock-bot/shutdown';
|
||||||
|
|
||||||
|
// Local imports
|
||||||
import { enhancedSyncManager } from './services/enhanced-sync-manager';
|
import { enhancedSyncManager } from './services/enhanced-sync-manager';
|
||||||
import { syncManager } from './services/sync-manager';
|
import { syncManager } from './services/sync-manager';
|
||||||
import { setMongoDBClient, setPostgreSQLClient } from './clients';
|
import { setMongoDBClient, setPostgreSQLClient } from './clients';
|
||||||
|
import { healthRoutes, syncRoutes, enhancedSyncRoutes, statsRoutes } from './routes';
|
||||||
|
|
||||||
// Initialize configuration with automatic monorepo config inheritance
|
// Initialize configuration with automatic monorepo config inheritance
|
||||||
const config = await initializeServiceConfig();
|
const config = await initializeServiceConfig();
|
||||||
|
|
@ -50,140 +57,11 @@ let mongoClient: MongoDBClient | null = null;
|
||||||
// Initialize shutdown manager
|
// Initialize shutdown manager
|
||||||
const shutdown = Shutdown.getInstance({ timeout: 15000 });
|
const shutdown = Shutdown.getInstance({ timeout: 15000 });
|
||||||
|
|
||||||
// Basic health check endpoint
|
// Mount routes
|
||||||
app.get('/health', c => {
|
app.route('/health', healthRoutes);
|
||||||
return c.json({
|
app.route('/sync', syncRoutes);
|
||||||
status: 'healthy',
|
app.route('/sync', enhancedSyncRoutes);
|
||||||
service: 'data-sync-service',
|
app.route('/sync/stats', statsRoutes);
|
||||||
timestamp: new Date().toISOString(),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Manual sync trigger endpoints
|
|
||||||
app.post('/sync/symbols', async c => {
|
|
||||||
try {
|
|
||||||
const result = await syncManager.syncQMSymbols();
|
|
||||||
return c.json({ success: true, result });
|
|
||||||
} catch (error) {
|
|
||||||
logger.error('Manual symbol sync failed', { error });
|
|
||||||
return c.json(
|
|
||||||
{ success: false, error: error instanceof Error ? error.message : 'Unknown error' },
|
|
||||||
500
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
app.post('/sync/exchanges', async c => {
|
|
||||||
try {
|
|
||||||
const result = await syncManager.syncQMExchanges();
|
|
||||||
return c.json({ success: true, result });
|
|
||||||
} catch (error) {
|
|
||||||
logger.error('Manual exchange sync failed', { error });
|
|
||||||
return c.json(
|
|
||||||
{ success: false, error: error instanceof Error ? error.message : 'Unknown error' },
|
|
||||||
500
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Get sync status
|
|
||||||
app.get('/sync/status', async c => {
|
|
||||||
try {
|
|
||||||
const status = await syncManager.getSyncStatus();
|
|
||||||
return c.json(status);
|
|
||||||
} catch (error) {
|
|
||||||
logger.error('Failed to get sync status', { error });
|
|
||||||
return c.json({ error: error instanceof Error ? error.message : 'Unknown error' }, 500);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Enhanced sync endpoints
|
|
||||||
app.post('/sync/exchanges/all', async c => {
|
|
||||||
try {
|
|
||||||
const clearFirst = c.req.query('clear') === 'true';
|
|
||||||
const result = await enhancedSyncManager.syncAllExchanges(clearFirst);
|
|
||||||
return c.json({ success: true, result });
|
|
||||||
} catch (error) {
|
|
||||||
logger.error('Enhanced exchange sync failed', { error });
|
|
||||||
return c.json(
|
|
||||||
{ success: false, error: error instanceof Error ? error.message : 'Unknown error' },
|
|
||||||
500
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
app.post('/sync/provider-mappings/qm', async c => {
|
|
||||||
try {
|
|
||||||
const result = await enhancedSyncManager.syncQMProviderMappings();
|
|
||||||
return c.json({ success: true, result });
|
|
||||||
} catch (error) {
|
|
||||||
logger.error('QM provider mappings sync failed', { error });
|
|
||||||
return c.json(
|
|
||||||
{ success: false, error: error instanceof Error ? error.message : 'Unknown error' },
|
|
||||||
500
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
app.post('/sync/symbols/:provider', async c => {
|
|
||||||
try {
|
|
||||||
const provider = c.req.param('provider');
|
|
||||||
const clearFirst = c.req.query('clear') === 'true';
|
|
||||||
const result = await enhancedSyncManager.syncSymbolsFromProvider(provider, clearFirst);
|
|
||||||
return c.json({ success: true, result });
|
|
||||||
} catch (error) {
|
|
||||||
logger.error('Enhanced symbol sync failed', { error });
|
|
||||||
return c.json(
|
|
||||||
{ success: false, error: error instanceof Error ? error.message : 'Unknown error' },
|
|
||||||
500
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Clear data endpoint
|
|
||||||
app.post('/sync/clear', async c => {
|
|
||||||
try {
|
|
||||||
const result = await enhancedSyncManager.clearPostgreSQLData();
|
|
||||||
return c.json({ success: true, result });
|
|
||||||
} catch (error) {
|
|
||||||
logger.error('Clear PostgreSQL data failed', { error });
|
|
||||||
return c.json(
|
|
||||||
{ success: false, error: error instanceof Error ? error.message : 'Unknown error' },
|
|
||||||
500
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Enhanced status endpoints
|
|
||||||
app.get('/sync/status/enhanced', async c => {
|
|
||||||
try {
|
|
||||||
const status = await enhancedSyncManager.getSyncStatus();
|
|
||||||
return c.json(status);
|
|
||||||
} catch (error) {
|
|
||||||
logger.error('Failed to get enhanced sync status', { error });
|
|
||||||
return c.json({ error: error instanceof Error ? error.message : 'Unknown error' }, 500);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
app.get('/sync/stats/exchanges', async c => {
|
|
||||||
try {
|
|
||||||
const stats = await enhancedSyncManager.getExchangeStats();
|
|
||||||
return c.json(stats);
|
|
||||||
} catch (error) {
|
|
||||||
logger.error('Failed to get exchange stats', { error });
|
|
||||||
return c.json({ error: error instanceof Error ? error.message : 'Unknown error' }, 500);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
app.get('/sync/stats/provider-mappings', async c => {
|
|
||||||
try {
|
|
||||||
const stats = await enhancedSyncManager.getProviderMappingStats();
|
|
||||||
return c.json(stats);
|
|
||||||
} catch (error) {
|
|
||||||
logger.error('Failed to get provider mapping stats', { error });
|
|
||||||
return c.json({ error: error instanceof Error ? error.message : 'Unknown error' }, 500);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Initialize services
|
// Initialize services
|
||||||
async function initializeServices() {
|
async function initializeServices() {
|
||||||
|
|
|
||||||
62
apps/data-sync-service/src/routes/enhanced-sync.routes.ts
Normal file
62
apps/data-sync-service/src/routes/enhanced-sync.routes.ts
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
import { Hono } from 'hono';
|
||||||
|
import { getLogger } from '@stock-bot/logger';
|
||||||
|
import { enhancedSyncManager } from '../services/enhanced-sync-manager';
|
||||||
|
|
||||||
|
const logger = getLogger('enhanced-sync-routes');
|
||||||
|
const enhancedSync = new Hono();
|
||||||
|
|
||||||
|
// Enhanced sync endpoints
|
||||||
|
enhancedSync.post('/exchanges/all', async c => {
|
||||||
|
try {
|
||||||
|
const clearFirst = c.req.query('clear') === 'true';
|
||||||
|
const result = await enhancedSyncManager.syncAllExchanges(clearFirst);
|
||||||
|
return c.json({ success: true, result });
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('Enhanced exchange sync failed', { error });
|
||||||
|
return c.json(
|
||||||
|
{ success: false, error: error instanceof Error ? error.message : 'Unknown error' },
|
||||||
|
500
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
enhancedSync.post('/provider-mappings/qm', async c => {
|
||||||
|
try {
|
||||||
|
const result = await enhancedSyncManager.syncQMProviderMappings();
|
||||||
|
return c.json({ success: true, result });
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('QM provider mappings sync failed', { error });
|
||||||
|
return c.json(
|
||||||
|
{ success: false, error: error instanceof Error ? error.message : 'Unknown error' },
|
||||||
|
500
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
enhancedSync.post('/symbols/:provider', async c => {
|
||||||
|
try {
|
||||||
|
const provider = c.req.param('provider');
|
||||||
|
const clearFirst = c.req.query('clear') === 'true';
|
||||||
|
const result = await enhancedSyncManager.syncSymbolsFromProvider(provider, clearFirst);
|
||||||
|
return c.json({ success: true, result });
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('Enhanced symbol sync failed', { error });
|
||||||
|
return c.json(
|
||||||
|
{ success: false, error: error instanceof Error ? error.message : 'Unknown error' },
|
||||||
|
500
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Enhanced status endpoints
|
||||||
|
enhancedSync.get('/status/enhanced', async c => {
|
||||||
|
try {
|
||||||
|
const status = await enhancedSyncManager.getSyncStatus();
|
||||||
|
return c.json(status);
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('Failed to get enhanced sync status', { error });
|
||||||
|
return c.json({ error: error instanceof Error ? error.message : 'Unknown error' }, 500);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export { enhancedSync as enhancedSyncRoutes };
|
||||||
14
apps/data-sync-service/src/routes/health.routes.ts
Normal file
14
apps/data-sync-service/src/routes/health.routes.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
import { Hono } from 'hono';
|
||||||
|
|
||||||
|
const health = new Hono();
|
||||||
|
|
||||||
|
// Basic health check endpoint
|
||||||
|
health.get('/', c => {
|
||||||
|
return c.json({
|
||||||
|
status: 'healthy',
|
||||||
|
service: 'data-sync-service',
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
export { health as healthRoutes };
|
||||||
5
apps/data-sync-service/src/routes/index.ts
Normal file
5
apps/data-sync-service/src/routes/index.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
// Export all route modules
|
||||||
|
export { healthRoutes } from './health.routes';
|
||||||
|
export { syncRoutes } from './sync.routes';
|
||||||
|
export { enhancedSyncRoutes } from './enhanced-sync.routes';
|
||||||
|
export { statsRoutes } from './stats.routes';
|
||||||
29
apps/data-sync-service/src/routes/stats.routes.ts
Normal file
29
apps/data-sync-service/src/routes/stats.routes.ts
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
import { Hono } from 'hono';
|
||||||
|
import { getLogger } from '@stock-bot/logger';
|
||||||
|
import { enhancedSyncManager } from '../services/enhanced-sync-manager';
|
||||||
|
|
||||||
|
const logger = getLogger('stats-routes');
|
||||||
|
const stats = new Hono();
|
||||||
|
|
||||||
|
// Statistics endpoints
|
||||||
|
stats.get('/exchanges', async c => {
|
||||||
|
try {
|
||||||
|
const statsData = await enhancedSyncManager.getExchangeStats();
|
||||||
|
return c.json(statsData);
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('Failed to get exchange stats', { error });
|
||||||
|
return c.json({ error: error instanceof Error ? error.message : 'Unknown error' }, 500);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
stats.get('/provider-mappings', async c => {
|
||||||
|
try {
|
||||||
|
const statsData = await enhancedSyncManager.getProviderMappingStats();
|
||||||
|
return c.json(statsData);
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('Failed to get provider mapping stats', { error });
|
||||||
|
return c.json({ error: error instanceof Error ? error.message : 'Unknown error' }, 500);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export { stats as statsRoutes };
|
||||||
61
apps/data-sync-service/src/routes/sync.routes.ts
Normal file
61
apps/data-sync-service/src/routes/sync.routes.ts
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
import { Hono } from 'hono';
|
||||||
|
import { getLogger } from '@stock-bot/logger';
|
||||||
|
import { syncManager } from '../services/sync-manager';
|
||||||
|
import { enhancedSyncManager } from '../services/enhanced-sync-manager';
|
||||||
|
|
||||||
|
const logger = getLogger('sync-routes');
|
||||||
|
const sync = new Hono();
|
||||||
|
|
||||||
|
// Manual sync trigger endpoints
|
||||||
|
sync.post('/symbols', async c => {
|
||||||
|
try {
|
||||||
|
const result = await syncManager.syncQMSymbols();
|
||||||
|
return c.json({ success: true, result });
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('Manual symbol sync failed', { error });
|
||||||
|
return c.json(
|
||||||
|
{ success: false, error: error instanceof Error ? error.message : 'Unknown error' },
|
||||||
|
500
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
sync.post('/exchanges', async c => {
|
||||||
|
try {
|
||||||
|
const result = await syncManager.syncQMExchanges();
|
||||||
|
return c.json({ success: true, result });
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('Manual exchange sync failed', { error });
|
||||||
|
return c.json(
|
||||||
|
{ success: false, error: error instanceof Error ? error.message : 'Unknown error' },
|
||||||
|
500
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Get sync status
|
||||||
|
sync.get('/status', async c => {
|
||||||
|
try {
|
||||||
|
const status = await syncManager.getSyncStatus();
|
||||||
|
return c.json(status);
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('Failed to get sync status', { error });
|
||||||
|
return c.json({ error: error instanceof Error ? error.message : 'Unknown error' }, 500);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Clear data endpoint
|
||||||
|
sync.post('/clear', async c => {
|
||||||
|
try {
|
||||||
|
const result = await enhancedSyncManager.clearPostgreSQLData();
|
||||||
|
return c.json({ success: true, result });
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('Clear PostgreSQL data failed', { error });
|
||||||
|
return c.json(
|
||||||
|
{ success: false, error: error instanceof Error ? error.message : 'Unknown error' },
|
||||||
|
500
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export { sync as syncRoutes };
|
||||||
Loading…
Add table
Add a link
Reference in a new issue