huge refactor to remove depenencie hell and add typesafe container

This commit is contained in:
Boki 2025-06-24 09:37:51 -04:00
parent 28b9822d55
commit 843a7b9b9b
148 changed files with 3603 additions and 2378 deletions

View file

@ -1,34 +1,34 @@
/**
* Service Container Setup for Data Pipeline
* Configures dependency injection for the data pipeline service
*/
import type { IServiceContainer } from '@stock-bot/handlers';
import { getLogger } from '@stock-bot/logger';
import type { AppConfig } from '@stock-bot/config';
const logger = getLogger('data-pipeline-container');
/**
* Configure the service container for data pipeline workloads
*/
export function setupServiceContainer(
config: AppConfig,
container: IServiceContainer
): IServiceContainer {
logger.info('Configuring data pipeline service container...');
// Data pipeline specific configuration
// This service does more complex queries and transformations
const poolSizes = {
mongodb: config.environment === 'production' ? 40 : 20,
postgres: config.environment === 'production' ? 50 : 25,
cache: config.environment === 'production' ? 30 : 15,
};
logger.info('Data pipeline pool sizes configured', poolSizes);
// The container is already configured with connections
// Just return it with our logging
return container;
}
/**
* Service Container Setup for Data Pipeline
* Configures dependency injection for the data pipeline service
*/
import type { AppConfig } from '@stock-bot/config';
import type { IServiceContainer } from '@stock-bot/handlers';
import { getLogger } from '@stock-bot/logger';
const logger = getLogger('data-pipeline-container');
/**
* Configure the service container for data pipeline workloads
*/
export function setupServiceContainer(
config: AppConfig,
container: IServiceContainer
): IServiceContainer {
logger.info('Configuring data pipeline service container...');
// Data pipeline specific configuration
// This service does more complex queries and transformations
const poolSizes = {
mongodb: config.environment === 'production' ? 40 : 20,
postgres: config.environment === 'production' ? 50 : 25,
cache: config.environment === 'production' ? 30 : 15,
};
logger.info('Data pipeline pool sizes configured', poolSizes);
// The container is already configured with connections
// Just return it with our logging
return container;
}

View file

@ -1,111 +1,113 @@
import {
BaseHandler,
Handler,
Operation,
ScheduledOperation,
type IServiceContainer,
} from '@stock-bot/handlers';
import { clearPostgreSQLData } from './operations/clear-postgresql-data.operations';
import { getSyncStatus } from './operations/enhanced-sync-status.operations';
import { getExchangeStats } from './operations/exchange-stats.operations';
import { getProviderMappingStats } from './operations/provider-mapping-stats.operations';
import { syncQMExchanges } from './operations/qm-exchanges.operations';
import { syncAllExchanges } from './operations/sync-all-exchanges.operations';
import { syncIBExchanges } from './operations/sync-ib-exchanges.operations';
import { syncQMProviderMappings } from './operations/sync-qm-provider-mappings.operations';
@Handler('exchanges')
class ExchangesHandler extends BaseHandler {
constructor(services: IServiceContainer) {
super(services);
}
/**
* Sync all exchanges - weekly full sync
*/
@Operation('sync-all-exchanges')
@ScheduledOperation('sync-all-exchanges', '0 0 * * 0', {
priority: 10,
description: 'Weekly full exchange sync on Sunday at midnight',
})
async syncAllExchanges(payload?: { clearFirst?: boolean }): Promise<unknown> {
const finalPayload = payload || { clearFirst: true };
this.log('info', 'Starting sync of all exchanges', finalPayload);
return syncAllExchanges(finalPayload, this.services);
}
/**
* Sync exchanges from QuestionsAndMethods
*/
@Operation('sync-qm-exchanges')
@ScheduledOperation('sync-qm-exchanges', '0 1 * * *', {
priority: 5,
description: 'Daily sync of QM exchanges at 1 AM',
})
async syncQMExchanges(): Promise<unknown> {
this.log('info', 'Starting QM exchanges sync...');
return syncQMExchanges({}, this.services);
}
/**
* Sync exchanges from Interactive Brokers
*/
@Operation('sync-ib-exchanges')
@ScheduledOperation('sync-ib-exchanges', '0 3 * * *', {
priority: 3,
description: 'Daily sync of IB exchanges at 3 AM',
})
async syncIBExchanges(): Promise<unknown> {
this.log('info', 'Starting IB exchanges sync...');
return syncIBExchanges({}, this.services);
}
/**
* Sync provider mappings from QuestionsAndMethods
*/
@Operation('sync-qm-provider-mappings')
@ScheduledOperation('sync-qm-provider-mappings', '0 3 * * *', {
priority: 7,
description: 'Daily sync of QM provider mappings at 3 AM',
})
async syncQMProviderMappings(): Promise<unknown> {
this.log('info', 'Starting QM provider mappings sync...');
return syncQMProviderMappings({}, this.services);
}
/**
* Clear PostgreSQL data - maintenance operation
*/
@Operation('clear-postgresql-data')
async clearPostgreSQLData(payload: { type?: 'exchanges' | 'provider_mappings' | 'all' }): Promise<unknown> {
this.log('warn', 'Clearing PostgreSQL data', payload);
return clearPostgreSQLData(payload, this.services);
}
/**
* Get exchange statistics
*/
@Operation('get-exchange-stats')
async getExchangeStats(): Promise<unknown> {
this.log('info', 'Getting exchange statistics...');
return getExchangeStats({}, this.services);
}
/**
* Get provider mapping statistics
*/
@Operation('get-provider-mapping-stats')
async getProviderMappingStats(): Promise<unknown> {
this.log('info', 'Getting provider mapping statistics...');
return getProviderMappingStats({}, this.services);
}
/**
* Get enhanced sync status
*/
@Operation('enhanced-sync-status')
async getEnhancedSyncStatus(): Promise<unknown> {
this.log('info', 'Getting enhanced sync status...');
return getSyncStatus({}, this.services);
}
}
import {
BaseHandler,
Handler,
Operation,
ScheduledOperation,
} from '@stock-bot/handlers';
import type { IServiceContainer } from '@stock-bot/types';
import { clearPostgreSQLData } from './operations/clear-postgresql-data.operations';
import { getSyncStatus } from './operations/enhanced-sync-status.operations';
import { getExchangeStats } from './operations/exchange-stats.operations';
import { getProviderMappingStats } from './operations/provider-mapping-stats.operations';
import { syncQMExchanges } from './operations/qm-exchanges.operations';
import { syncAllExchanges } from './operations/sync-all-exchanges.operations';
import { syncIBExchanges } from './operations/sync-ib-exchanges.operations';
import { syncQMProviderMappings } from './operations/sync-qm-provider-mappings.operations';
@Handler('exchanges')
class ExchangesHandler extends BaseHandler {
constructor(services: IServiceContainer) {
super(services);
}
/**
* Sync all exchanges - weekly full sync
*/
@Operation('sync-all-exchanges')
@ScheduledOperation('sync-all-exchanges', '0 0 * * 0', {
priority: 10,
description: 'Weekly full exchange sync on Sunday at midnight',
})
async syncAllExchanges(payload?: { clearFirst?: boolean }): Promise<unknown> {
const finalPayload = payload || { clearFirst: true };
this.log('info', 'Starting sync of all exchanges', finalPayload);
return syncAllExchanges(finalPayload, this.services);
}
/**
* Sync exchanges from QuestionsAndMethods
*/
@Operation('sync-qm-exchanges')
@ScheduledOperation('sync-qm-exchanges', '0 1 * * *', {
priority: 5,
description: 'Daily sync of QM exchanges at 1 AM',
})
async syncQMExchanges(): Promise<unknown> {
this.log('info', 'Starting QM exchanges sync...');
return syncQMExchanges({}, this.services);
}
/**
* Sync exchanges from Interactive Brokers
*/
@Operation('sync-ib-exchanges')
@ScheduledOperation('sync-ib-exchanges', '0 3 * * *', {
priority: 3,
description: 'Daily sync of IB exchanges at 3 AM',
})
async syncIBExchanges(): Promise<unknown> {
this.log('info', 'Starting IB exchanges sync...');
return syncIBExchanges({}, this.services);
}
/**
* Sync provider mappings from QuestionsAndMethods
*/
@Operation('sync-qm-provider-mappings')
@ScheduledOperation('sync-qm-provider-mappings', '0 3 * * *', {
priority: 7,
description: 'Daily sync of QM provider mappings at 3 AM',
})
async syncQMProviderMappings(): Promise<unknown> {
this.log('info', 'Starting QM provider mappings sync...');
return syncQMProviderMappings({}, this.services);
}
/**
* Clear PostgreSQL data - maintenance operation
*/
@Operation('clear-postgresql-data')
async clearPostgreSQLData(payload: {
type?: 'exchanges' | 'provider_mappings' | 'all';
}): Promise<unknown> {
this.log('warn', 'Clearing PostgreSQL data', payload);
return clearPostgreSQLData(payload, this.services);
}
/**
* Get exchange statistics
*/
@Operation('get-exchange-stats')
async getExchangeStats(): Promise<unknown> {
this.log('info', 'Getting exchange statistics...');
return getExchangeStats({}, this.services);
}
/**
* Get provider mapping statistics
*/
@Operation('get-provider-mapping-stats')
async getProviderMappingStats(): Promise<unknown> {
this.log('info', 'Getting provider mapping statistics...');
return getProviderMappingStats({}, this.services);
}
/**
* Get enhanced sync status
*/
@Operation('enhanced-sync-status')
async getEnhancedSyncStatus(): Promise<unknown> {
this.log('info', 'Getting enhanced sync status...');
return getSyncStatus({}, this.services);
}
}

View file

@ -1,5 +1,5 @@
import { getLogger } from '@stock-bot/logger';
import type { IServiceContainer } from '@stock-bot/handlers';
import { getLogger } from '@stock-bot/logger';
import type { JobPayload } from '../../../types/job-payloads';
const logger = getLogger('enhanced-sync-clear-postgresql-data');

View file

@ -1,5 +1,5 @@
import { getLogger } from '@stock-bot/logger';
import type { IServiceContainer } from '@stock-bot/handlers';
import { getLogger } from '@stock-bot/logger';
import type { JobPayload, SyncStatus } from '../../../types/job-payloads';
const logger = getLogger('enhanced-sync-status');

View file

@ -1,5 +1,5 @@
import { getLogger } from '@stock-bot/logger';
import type { IServiceContainer } from '@stock-bot/handlers';
import { getLogger } from '@stock-bot/logger';
import type { JobPayload } from '../../../types/job-payloads';
const logger = getLogger('enhanced-sync-exchange-stats');

View file

@ -1,5 +1,5 @@
import { getLogger } from '@stock-bot/logger';
import type { IServiceContainer } from '@stock-bot/handlers';
import { getLogger } from '@stock-bot/logger';
import type { JobPayload } from '../../../types/job-payloads';
const logger = getLogger('enhanced-sync-provider-mapping-stats');

View file

@ -1,5 +1,5 @@
import type { IServiceContainer } from '@stock-bot/types';
import { getLogger } from '@stock-bot/logger';
import type { IServiceContainer } from '@stock-bot/handlers';
import type { JobPayload } from '../../../types/job-payloads';
const logger = getLogger('sync-qm-exchanges');
@ -62,7 +62,10 @@ interface Exchange {
visible: boolean;
}
async function findExchange(exchangeCode: string, postgresClient: IServiceContainer['postgres']): Promise<Exchange | null> {
async function findExchange(
exchangeCode: string,
postgresClient: IServiceContainer['postgres']
): Promise<Exchange | null> {
const query = 'SELECT * FROM exchanges WHERE code = $1';
const result = await postgresClient.query(query, [exchangeCode]);
return result.rows[0] || null;
@ -76,7 +79,10 @@ interface QMExchange {
countryCode?: string;
}
async function createExchange(qmExchange: QMExchange, postgresClient: IServiceContainer['postgres']): Promise<void> {
async function createExchange(
qmExchange: QMExchange,
postgresClient: IServiceContainer['postgres']
): Promise<void> {
const query = `
INSERT INTO exchanges (code, name, country, currency, visible)
VALUES ($1, $2, $3, $4, $5)

View file

@ -1,10 +1,13 @@
import { getLogger } from '@stock-bot/logger';
import type { IServiceContainer } from '@stock-bot/handlers';
import { getLogger } from '@stock-bot/logger';
import type { JobPayload, SyncResult } from '../../../types/job-payloads';
const logger = getLogger('enhanced-sync-all-exchanges');
export async function syncAllExchanges(payload: JobPayload, container: IServiceContainer): Promise<SyncResult> {
export async function syncAllExchanges(
payload: JobPayload,
container: IServiceContainer
): Promise<SyncResult> {
const clearFirst = payload.clearFirst || true;
logger.info('Starting comprehensive exchange sync...', { clearFirst });
@ -50,7 +53,6 @@ export async function syncAllExchanges(payload: JobPayload, container: IServiceC
}
}
async function clearPostgreSQLData(postgresClient: any): Promise<void> {
logger.info('Clearing existing PostgreSQL data...');
@ -141,7 +143,11 @@ async function createProviderExchangeMapping(
const postgresClient = container.postgres;
// Check if mapping already exists
const existingMapping = await findProviderExchangeMapping(provider, providerExchangeCode, container);
const existingMapping = await findProviderExchangeMapping(
provider,
providerExchangeCode,
container
);
if (existingMapping) {
// Don't override existing mappings to preserve manual work
return;

View file

@ -1,6 +1,6 @@
import type { IServiceContainer } from '@stock-bot/handlers';
import { getLogger } from '@stock-bot/logger';
import type { MasterExchange } from '@stock-bot/mongodb';
import type { IServiceContainer } from '@stock-bot/handlers';
import type { JobPayload } from '../../../types/job-payloads';
const logger = getLogger('sync-ib-exchanges');
@ -65,7 +65,10 @@ export async function syncIBExchanges(
/**
* Create or update master exchange record 1:1 from IB exchange
*/
async function createOrUpdateMasterExchange(ibExchange: IBExchange, container: IServiceContainer): Promise<void> {
async function createOrUpdateMasterExchange(
ibExchange: IBExchange,
container: IServiceContainer
): Promise<void> {
const mongoClient = container.mongodb;
const db = mongoClient.getDatabase();
const collection = db.collection<MasterExchange>('masterExchanges');

View file

@ -1,5 +1,5 @@
import { getLogger } from '@stock-bot/logger';
import type { IServiceContainer } from '@stock-bot/handlers';
import { getLogger } from '@stock-bot/logger';
import type { JobPayload, SyncResult } from '../../../types/job-payloads';
const logger = getLogger('enhanced-sync-qm-provider-mappings');
@ -86,7 +86,6 @@ export async function syncQMProviderMappings(
}
}
async function createProviderExchangeMapping(
provider: string,
providerExchangeCode: string,
@ -103,7 +102,11 @@ async function createProviderExchangeMapping(
const postgresClient = container.postgres;
// Check if mapping already exists
const existingMapping = await findProviderExchangeMapping(provider, providerExchangeCode, container);
const existingMapping = await findProviderExchangeMapping(
provider,
providerExchangeCode,
container
);
if (existingMapping) {
// Don't override existing mappings to preserve manual work
return;

View file

@ -1,42 +1,41 @@
/**
* Handler auto-registration for data pipeline service
* Automatically discovers and registers all handlers
*/
import type { IServiceContainer } from '@stock-bot/handlers';
import { autoRegisterHandlers } from '@stock-bot/handlers';
import { getLogger } from '@stock-bot/logger';
// Import handlers for bundling (ensures they're included in the build)
import './exchanges/exchanges.handler';
import './symbols/symbols.handler';
const logger = getLogger('pipeline-handler-init');
/**
* Initialize and register all handlers automatically
*/
export async function initializeAllHandlers(container: IServiceContainer): Promise<void> {
logger.info('Initializing data pipeline handlers...');
try {
// Auto-register all handlers in this directory
const result = await autoRegisterHandlers(__dirname, container, {
pattern: '.handler.',
exclude: ['test', 'spec', '.old'],
dryRun: false,
});
logger.info('Handler auto-registration complete', {
registered: result.registered,
failed: result.failed,
});
if (result.failed.length > 0) {
logger.error('Some handlers failed to register', { failed: result.failed });
}
} catch (error) {
logger.error('Handler auto-registration failed', { error });
throw error;
}
}
/**
* Handler auto-registration for data pipeline service
* Automatically discovers and registers all handlers
*/
import type { IServiceContainer } from '@stock-bot/handlers';
import { autoRegisterHandlers } from '@stock-bot/handlers';
import { getLogger } from '@stock-bot/logger';
// Import handlers for bundling (ensures they're included in the build)
import './exchanges/exchanges.handler';
import './symbols/symbols.handler';
const logger = getLogger('pipeline-handler-init');
/**
* Initialize and register all handlers automatically
*/
export async function initializeAllHandlers(container: IServiceContainer): Promise<void> {
logger.info('Initializing data pipeline handlers...');
try {
// Auto-register all handlers in this directory
const result = await autoRegisterHandlers(__dirname, container, {
pattern: '.handler.',
exclude: ['test', 'spec', '.old'],
dryRun: false,
});
logger.info('Handler auto-registration complete', {
registered: result.registered,
failed: result.failed,
});
if (result.failed.length > 0) {
logger.error('Some handlers failed to register', { failed: result.failed });
}
} catch (error) {
logger.error('Handler auto-registration failed', { error });
throw error;
}
}

View file

@ -1,5 +1,5 @@
import { getLogger } from '@stock-bot/logger';
import type { IServiceContainer } from '@stock-bot/handlers';
import { getLogger } from '@stock-bot/logger';
import type { JobPayload } from '../../../types/job-payloads';
const logger = getLogger('sync-qm-symbols');

View file

@ -1,5 +1,5 @@
import { getLogger } from '@stock-bot/logger';
import type { IServiceContainer } from '@stock-bot/handlers';
import { getLogger } from '@stock-bot/logger';
import type { JobPayload } from '../../../types/job-payloads';
const logger = getLogger('sync-status');

View file

@ -1,5 +1,5 @@
import { getLogger } from '@stock-bot/logger';
import type { IServiceContainer } from '@stock-bot/handlers';
import { getLogger } from '@stock-bot/logger';
import type { JobPayload, SyncResult } from '../../../types/job-payloads';
const logger = getLogger('enhanced-sync-symbols-from-provider');
@ -104,7 +104,11 @@ async function processSingleSymbol(
}
// Find active provider exchange mapping
const providerMapping = await findActiveProviderExchangeMapping(provider, exchangeCode, container);
const providerMapping = await findActiveProviderExchangeMapping(
provider,
exchangeCode,
container
);
if (!providerMapping) {
result.skipped++;
@ -145,14 +149,22 @@ async function findActiveProviderExchangeMapping(
return result.rows[0] || null;
}
async function findSymbolByCodeAndExchange(symbol: string, exchangeId: string, container: IServiceContainer): Promise<any> {
async function findSymbolByCodeAndExchange(
symbol: string,
exchangeId: string,
container: IServiceContainer
): Promise<any> {
const postgresClient = container.postgres;
const query = 'SELECT * FROM symbols WHERE symbol = $1 AND exchange_id = $2';
const result = await postgresClient.query(query, [symbol, exchangeId]);
return result.rows[0] || null;
}
async function createSymbol(symbol: any, exchangeId: string, container: IServiceContainer): Promise<string> {
async function createSymbol(
symbol: any,
exchangeId: string,
container: IServiceContainer
): Promise<string> {
const postgresClient = container.postgres;
const query = `
INSERT INTO symbols (symbol, exchange_id, company_name, country, currency)
@ -171,7 +183,11 @@ async function createSymbol(symbol: any, exchangeId: string, container: IService
return result.rows[0].id;
}
async function updateSymbol(symbolId: string, symbol: any, container: IServiceContainer): Promise<void> {
async function updateSymbol(
symbolId: string,
symbol: any,
container: IServiceContainer
): Promise<void> {
const postgresClient = container.postgres;
const query = `
UPDATE symbols

View file

@ -1,68 +1,71 @@
import {
BaseHandler,
Handler,
Operation,
ScheduledOperation,
type IServiceContainer,
} from '@stock-bot/handlers';
import { syncQMSymbols } from './operations/qm-symbols.operations';
import { syncSymbolsFromProvider } from './operations/sync-symbols-from-provider.operations';
import { getSyncStatus } from './operations/sync-status.operations';
@Handler('symbols')
class SymbolsHandler extends BaseHandler {
constructor(services: IServiceContainer) {
super(services);
}
/**
* Sync symbols from QuestionsAndMethods API
*/
@ScheduledOperation('sync-qm-symbols', '0 2 * * *', {
priority: 5,
description: 'Daily sync of QM symbols at 2 AM',
})
async syncQMSymbols(): Promise<{ processed: number; created: number; updated: number }> {
this.log('info', 'Starting QM symbols sync...');
return syncQMSymbols({}, this.services);
}
/**
* Sync symbols from specific provider
*/
@Operation('sync-symbols-qm')
@ScheduledOperation('sync-symbols-qm', '0 4 * * *', {
priority: 5,
description: 'Daily sync of symbols from QM provider at 4 AM',
})
async syncSymbolsQM(): Promise<unknown> {
return this.syncSymbolsFromProvider({ provider: 'qm', clearFirst: false });
}
@Operation('sync-symbols-eod')
async syncSymbolsEOD(payload: { provider: string; clearFirst?: boolean }): Promise<unknown> {
return this.syncSymbolsFromProvider({ ...payload, provider: 'eod' });
}
@Operation('sync-symbols-ib')
async syncSymbolsIB(payload: { provider: string; clearFirst?: boolean }): Promise<unknown> {
return this.syncSymbolsFromProvider({ ...payload, provider: 'ib' });
}
/**
* Get sync status for symbols
*/
@Operation('sync-status')
async getSyncStatus(): Promise<unknown> {
this.log('info', 'Getting symbol sync status...');
return getSyncStatus({}, this.services);
}
/**
* Internal method to sync symbols from a provider
*/
private async syncSymbolsFromProvider(payload: { provider: string; clearFirst?: boolean }): Promise<unknown> {
this.log('info', 'Syncing symbols from provider', { provider: payload.provider });
return syncSymbolsFromProvider(payload, this.services);
}
}
import {
BaseHandler,
Handler,
Operation,
ScheduledOperation,
type IServiceContainer,
} from '@stock-bot/handlers';
import { syncQMSymbols } from './operations/qm-symbols.operations';
import { getSyncStatus } from './operations/sync-status.operations';
import { syncSymbolsFromProvider } from './operations/sync-symbols-from-provider.operations';
@Handler('symbols')
class SymbolsHandler extends BaseHandler {
constructor(services: IServiceContainer) {
super(services);
}
/**
* Sync symbols from QuestionsAndMethods API
*/
@ScheduledOperation('sync-qm-symbols', '0 2 * * *', {
priority: 5,
description: 'Daily sync of QM symbols at 2 AM',
})
async syncQMSymbols(): Promise<{ processed: number; created: number; updated: number }> {
this.log('info', 'Starting QM symbols sync...');
return syncQMSymbols({}, this.services);
}
/**
* Sync symbols from specific provider
*/
@Operation('sync-symbols-qm')
@ScheduledOperation('sync-symbols-qm', '0 4 * * *', {
priority: 5,
description: 'Daily sync of symbols from QM provider at 4 AM',
})
async syncSymbolsQM(): Promise<unknown> {
return this.syncSymbolsFromProvider({ provider: 'qm', clearFirst: false });
}
@Operation('sync-symbols-eod')
async syncSymbolsEOD(payload: { provider: string; clearFirst?: boolean }): Promise<unknown> {
return this.syncSymbolsFromProvider({ ...payload, provider: 'eod' });
}
@Operation('sync-symbols-ib')
async syncSymbolsIB(payload: { provider: string; clearFirst?: boolean }): Promise<unknown> {
return this.syncSymbolsFromProvider({ ...payload, provider: 'ib' });
}
/**
* Get sync status for symbols
*/
@Operation('sync-status')
async getSyncStatus(): Promise<unknown> {
this.log('info', 'Getting symbol sync status...');
return getSyncStatus({}, this.services);
}
/**
* Internal method to sync symbols from a provider
*/
private async syncSymbolsFromProvider(payload: {
provider: string;
clearFirst?: boolean;
}): Promise<unknown> {
this.log('info', 'Syncing symbols from provider', { provider: payload.provider });
return syncSymbolsFromProvider(payload, this.services);
}
}

View file

@ -3,14 +3,13 @@
* Simplified entry point using ServiceApplication framework
*/
import { initializeStockConfig } from '@stock-bot/stock-config';
import { ServiceApplication } from '@stock-bot/di';
import { getLogger } from '@stock-bot/logger';
// Local imports
import { initializeAllHandlers } from './handlers';
import { initializeStockConfig } from '@stock-bot/stock-config';
import { createRoutes } from './routes/create-routes';
import { setupServiceContainer } from './container-setup';
// Local imports
import { initializeAllHandlers } from './handlers';
// Initialize configuration with service-specific overrides
const config = initializeStockConfig('dataPipeline');
@ -43,12 +42,12 @@ const app = new ServiceApplication(
},
{
// Custom lifecycle hooks
onContainerReady: (container) => {
onContainerReady: container => {
// Setup service-specific configuration
const enhancedContainer = setupServiceContainer(config, container);
return enhancedContainer;
},
onStarted: (_port) => {
onStarted: _port => {
const logger = getLogger('data-pipeline');
logger.info('Data pipeline service startup initiated with ServiceApplication framework');
},
@ -59,7 +58,7 @@ const app = new ServiceApplication(
async function createContainer(config: any) {
const { ServiceContainerBuilder } = await import('@stock-bot/di');
const builder = new ServiceContainerBuilder();
const container = await builder
.withConfig(config)
.withOptions({
@ -74,7 +73,7 @@ async function createContainer(config: any) {
skipInitialization: false, // Let builder handle initialization
})
.build();
return container;
}
@ -83,4 +82,4 @@ app.start(createContainer, createRoutes, initializeAllHandlers).catch(error => {
const logger = getLogger('data-pipeline');
logger.fatal('Failed to start data pipeline service', { error });
process.exit(1);
});
});

View file

@ -1,29 +1,29 @@
/**
* Route factory for data pipeline service
* Creates routes with access to the service container
*/
import { Hono } from 'hono';
import type { IServiceContainer } from '@stock-bot/handlers';
import { healthRoutes } from './health.routes';
import { createSyncRoutes } from './sync.routes';
import { createEnhancedSyncRoutes } from './enhanced-sync.routes';
import { createStatsRoutes } from './stats.routes';
export function createRoutes(container: IServiceContainer): Hono {
const app = new Hono();
// Add container to context for all routes
app.use('*', async (c, next) => {
c.set('container', container);
await next();
});
// Mount routes
app.route('/health', healthRoutes);
app.route('/sync', createSyncRoutes(container));
app.route('/sync', createEnhancedSyncRoutes(container));
app.route('/sync/stats', createStatsRoutes(container));
return app;
}
/**
* Route factory for data pipeline service
* Creates routes with access to the service container
*/
import { Hono } from 'hono';
import type { IServiceContainer } from '@stock-bot/handlers';
import { createEnhancedSyncRoutes } from './enhanced-sync.routes';
import { healthRoutes } from './health.routes';
import { createStatsRoutes } from './stats.routes';
import { createSyncRoutes } from './sync.routes';
export function createRoutes(container: IServiceContainer): Hono {
const app = new Hono();
// Add container to context for all routes
app.use('*', async (c, next) => {
c.set('container', container);
await next();
});
// Mount routes
app.route('/health', healthRoutes);
app.route('/sync', createSyncRoutes(container));
app.route('/sync', createEnhancedSyncRoutes(container));
app.route('/sync/stats', createStatsRoutes(container));
return app;
}

View file

@ -1,6 +1,6 @@
import { Hono } from 'hono';
import { getLogger } from '@stock-bot/logger';
import type { IServiceContainer } from '@stock-bot/handlers';
import { getLogger } from '@stock-bot/logger';
const logger = getLogger('enhanced-sync-routes');
@ -15,7 +15,7 @@ export function createEnhancedSyncRoutes(container: IServiceContainer) {
if (!queueManager) {
return c.json({ success: false, error: 'Queue manager not available' }, 503);
}
const exchangesQueue = queueManager.getQueue('exchanges');
const job = await exchangesQueue.addJob('sync-all-exchanges', {
@ -40,7 +40,7 @@ export function createEnhancedSyncRoutes(container: IServiceContainer) {
if (!queueManager) {
return c.json({ success: false, error: 'Queue manager not available' }, 503);
}
const exchangesQueue = queueManager.getQueue('exchanges');
const job = await exchangesQueue.addJob('sync-qm-provider-mappings', {
@ -69,7 +69,7 @@ export function createEnhancedSyncRoutes(container: IServiceContainer) {
if (!queueManager) {
return c.json({ success: false, error: 'Queue manager not available' }, 503);
}
const exchangesQueue = queueManager.getQueue('exchanges');
const job = await exchangesQueue.addJob('sync-ib-exchanges', {
@ -98,7 +98,7 @@ export function createEnhancedSyncRoutes(container: IServiceContainer) {
if (!queueManager) {
return c.json({ success: false, error: 'Queue manager not available' }, 503);
}
const symbolsQueue = queueManager.getQueue('symbols');
const job = await symbolsQueue.addJob('sync-status', {
@ -124,7 +124,7 @@ export function createEnhancedSyncRoutes(container: IServiceContainer) {
if (!queueManager) {
return c.json({ success: false, error: 'Queue manager not available' }, 503);
}
const exchangesQueue = queueManager.getQueue('exchanges');
const job = await exchangesQueue.addJob('clear-postgresql-data', {
@ -148,4 +148,4 @@ export function createEnhancedSyncRoutes(container: IServiceContainer) {
});
return enhancedSync;
}
}

View file

@ -1,6 +1,6 @@
import { Hono } from 'hono';
import { getLogger } from '@stock-bot/logger';
import type { IServiceContainer } from '@stock-bot/handlers';
import { getLogger } from '@stock-bot/logger';
const logger = getLogger('stats-routes');
@ -14,7 +14,7 @@ export function createStatsRoutes(container: IServiceContainer) {
if (!queueManager) {
return c.json({ error: 'Queue manager not available' }, 503);
}
const exchangesQueue = queueManager.getQueue('exchanges');
const job = await exchangesQueue.addJob('get-exchange-stats', {
@ -38,7 +38,7 @@ export function createStatsRoutes(container: IServiceContainer) {
if (!queueManager) {
return c.json({ error: 'Queue manager not available' }, 503);
}
const exchangesQueue = queueManager.getQueue('exchanges');
const job = await exchangesQueue.addJob('get-provider-mapping-stats', {
@ -57,4 +57,4 @@ export function createStatsRoutes(container: IServiceContainer) {
});
return stats;
}
}

View file

@ -1,6 +1,6 @@
import { Hono } from 'hono';
import { getLogger } from '@stock-bot/logger';
import type { IServiceContainer } from '@stock-bot/handlers';
import { getLogger } from '@stock-bot/logger';
const logger = getLogger('sync-routes');
@ -14,7 +14,7 @@ export function createSyncRoutes(container: IServiceContainer) {
if (!queueManager) {
return c.json({ success: false, error: 'Queue manager not available' }, 503);
}
const symbolsQueue = queueManager.getQueue('symbols');
const job = await symbolsQueue.addJob('sync-qm-symbols', {
@ -39,7 +39,7 @@ export function createSyncRoutes(container: IServiceContainer) {
if (!queueManager) {
return c.json({ success: false, error: 'Queue manager not available' }, 503);
}
const exchangesQueue = queueManager.getQueue('exchanges');
const job = await exchangesQueue.addJob('sync-qm-exchanges', {
@ -65,7 +65,7 @@ export function createSyncRoutes(container: IServiceContainer) {
if (!queueManager) {
return c.json({ success: false, error: 'Queue manager not available' }, 503);
}
const symbolsQueue = queueManager.getQueue('symbols');
const job = await symbolsQueue.addJob('sync-symbols-from-provider', {
@ -89,4 +89,4 @@ export function createSyncRoutes(container: IServiceContainer) {
});
return sync;
}
}