huge refactor to remove depenencie hell and add typesafe container
This commit is contained in:
parent
28b9822d55
commit
843a7b9b9b
148 changed files with 3603 additions and 2378 deletions
|
|
@ -1,15 +1,17 @@
|
|||
import { createContainer, InjectionMode, asFunction, type AwilixContainer } from 'awilix';
|
||||
import { asClass, asFunction, createContainer, InjectionMode, type AwilixContainer } from 'awilix';
|
||||
import type { BaseAppConfig as StockBotAppConfig, UnifiedAppConfig } from '@stock-bot/config';
|
||||
import { appConfigSchema, type AppConfig } from '../config/schemas';
|
||||
import { toUnifiedConfig } from '@stock-bot/config';
|
||||
import {
|
||||
registerCoreServices,
|
||||
import { HandlerRegistry } from '@stock-bot/handler-registry';
|
||||
import { appConfigSchema, type AppConfig } from '../config/schemas';
|
||||
import {
|
||||
registerApplicationServices,
|
||||
registerCacheServices,
|
||||
registerCoreServices,
|
||||
registerDatabaseServices,
|
||||
registerApplicationServices
|
||||
} from '../registrations';
|
||||
import { HandlerScanner } from '../scanner';
|
||||
import { ServiceLifecycleManager } from '../utils/lifecycle';
|
||||
import type { ServiceDefinitions, ContainerBuildOptions } from './types';
|
||||
import type { ContainerBuildOptions, ServiceDefinitions } from './types';
|
||||
|
||||
export class ServiceContainerBuilder {
|
||||
private config: Partial<AppConfig> = {};
|
||||
|
|
@ -38,7 +40,10 @@ export class ServiceContainerBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
enableService(service: keyof Omit<ContainerBuildOptions, 'skipInitialization' | 'initializationTimeout'>, enabled = true): this {
|
||||
enableService(
|
||||
service: keyof Omit<ContainerBuildOptions, 'skipInitialization' | 'initializationTimeout'>,
|
||||
enabled = true
|
||||
): this {
|
||||
this.options[service] = enabled;
|
||||
return this;
|
||||
}
|
||||
|
|
@ -51,7 +56,7 @@ export class ServiceContainerBuilder {
|
|||
async build(): Promise<AwilixContainer<ServiceDefinitions>> {
|
||||
// Validate and prepare config
|
||||
const validatedConfig = this.prepareConfig();
|
||||
|
||||
|
||||
// Create container
|
||||
const container = createContainer<ServiceDefinitions>({
|
||||
injectionMode: InjectionMode.PROXY,
|
||||
|
|
@ -77,17 +82,19 @@ export class ServiceContainerBuilder {
|
|||
|
||||
private applyServiceOptions(config: Partial<AppConfig>): AppConfig {
|
||||
// Ensure questdb config has the right field names for DI
|
||||
const questdbConfig = config.questdb ? {
|
||||
...config.questdb,
|
||||
influxPort: (config.questdb as any).influxPort || (config.questdb as any).ilpPort || 9009,
|
||||
} : {
|
||||
enabled: true,
|
||||
host: 'localhost',
|
||||
httpPort: 9000,
|
||||
pgPort: 8812,
|
||||
influxPort: 9009,
|
||||
database: 'questdb',
|
||||
};
|
||||
const questdbConfig = config.questdb
|
||||
? {
|
||||
...config.questdb,
|
||||
influxPort: (config.questdb as any).influxPort || (config.questdb as any).ilpPort || 9009,
|
||||
}
|
||||
: {
|
||||
enabled: true,
|
||||
host: 'localhost',
|
||||
httpPort: 9000,
|
||||
pgPort: 8812,
|
||||
influxPort: 9009,
|
||||
database: 'questdb',
|
||||
};
|
||||
|
||||
return {
|
||||
redis: config.redis || {
|
||||
|
|
@ -110,61 +117,88 @@ export class ServiceContainerBuilder {
|
|||
password: 'postgres',
|
||||
},
|
||||
questdb: this.options.enableQuestDB ? questdbConfig : undefined,
|
||||
proxy: this.options.enableProxy ? (config.proxy || { enabled: false, cachePrefix: 'proxy:', ttl: 3600 }) : undefined,
|
||||
browser: this.options.enableBrowser ? (config.browser || { headless: true, timeout: 30000 }) : undefined,
|
||||
queue: this.options.enableQueue ? (config.queue || {
|
||||
enabled: true,
|
||||
workers: 1,
|
||||
concurrency: 1,
|
||||
enableScheduledJobs: true,
|
||||
delayWorkerStart: false,
|
||||
defaultJobOptions: {
|
||||
attempts: 3,
|
||||
backoff: { type: 'exponential' as const, delay: 1000 },
|
||||
removeOnComplete: 100,
|
||||
removeOnFail: 50,
|
||||
}
|
||||
}) : undefined,
|
||||
proxy: this.options.enableProxy
|
||||
? config.proxy || { enabled: false, cachePrefix: 'proxy:', ttl: 3600 }
|
||||
: undefined,
|
||||
browser: this.options.enableBrowser
|
||||
? config.browser || { headless: true, timeout: 30000 }
|
||||
: undefined,
|
||||
queue: this.options.enableQueue
|
||||
? config.queue || {
|
||||
enabled: true,
|
||||
workers: 1,
|
||||
concurrency: 1,
|
||||
enableScheduledJobs: true,
|
||||
delayWorkerStart: false,
|
||||
defaultJobOptions: {
|
||||
attempts: 3,
|
||||
backoff: { type: 'exponential' as const, delay: 1000 },
|
||||
removeOnComplete: 100,
|
||||
removeOnFail: 50,
|
||||
},
|
||||
}
|
||||
: undefined,
|
||||
service: config.service,
|
||||
};
|
||||
}
|
||||
|
||||
private registerServices(container: AwilixContainer<ServiceDefinitions>, config: AppConfig): void {
|
||||
private registerServices(
|
||||
container: AwilixContainer<ServiceDefinitions>,
|
||||
config: AppConfig
|
||||
): void {
|
||||
// Register handler infrastructure first
|
||||
container.register({
|
||||
handlerRegistry: asClass(HandlerRegistry).singleton(),
|
||||
handlerScanner: asClass(HandlerScanner).singleton(),
|
||||
});
|
||||
|
||||
registerCoreServices(container, config);
|
||||
registerCacheServices(container, config);
|
||||
registerDatabaseServices(container, config);
|
||||
registerApplicationServices(container, config);
|
||||
|
||||
|
||||
// Register service container aggregate
|
||||
container.register({
|
||||
serviceContainer: asFunction(({
|
||||
config: _config, logger, cache, globalCache, proxyManager, browser,
|
||||
queueManager, mongoClient, postgresClient, questdbClient
|
||||
}) => ({
|
||||
logger,
|
||||
cache,
|
||||
globalCache,
|
||||
proxy: proxyManager, // Map proxyManager to proxy
|
||||
browser,
|
||||
queue: queueManager, // Map queueManager to queue
|
||||
mongodb: mongoClient, // Map mongoClient to mongodb
|
||||
postgres: postgresClient, // Map postgresClient to postgres
|
||||
questdb: questdbClient, // Map questdbClient to questdb
|
||||
})).singleton(),
|
||||
serviceContainer: asFunction(
|
||||
({
|
||||
config: _config,
|
||||
logger,
|
||||
cache,
|
||||
globalCache,
|
||||
proxyManager,
|
||||
browser,
|
||||
queueManager,
|
||||
mongoClient,
|
||||
postgresClient,
|
||||
questdbClient,
|
||||
}) => ({
|
||||
logger,
|
||||
cache,
|
||||
globalCache,
|
||||
proxy: proxyManager, // Map proxyManager to proxy
|
||||
browser,
|
||||
queue: queueManager, // Map queueManager to queue
|
||||
mongodb: mongoClient, // Map mongoClient to mongodb
|
||||
postgres: postgresClient, // Map postgresClient to postgres
|
||||
questdb: questdbClient, // Map questdbClient to questdb
|
||||
})
|
||||
).singleton(),
|
||||
});
|
||||
}
|
||||
|
||||
private transformStockBotConfig(config: UnifiedAppConfig): Partial<AppConfig> {
|
||||
// Unified config already has flat structure, just extract what we need
|
||||
// Handle questdb field name mapping
|
||||
const questdb = config.questdb ? {
|
||||
enabled: config.questdb.enabled || true,
|
||||
host: config.questdb.host || 'localhost',
|
||||
httpPort: config.questdb.httpPort || 9000,
|
||||
pgPort: config.questdb.pgPort || 8812,
|
||||
influxPort: (config.questdb as any).influxPort || (config.questdb as any).ilpPort || 9009,
|
||||
database: config.questdb.database || 'questdb',
|
||||
} : undefined;
|
||||
const questdb = config.questdb
|
||||
? {
|
||||
enabled: config.questdb.enabled || true,
|
||||
host: config.questdb.host || 'localhost',
|
||||
httpPort: config.questdb.httpPort || 9000,
|
||||
pgPort: config.questdb.pgPort || 8812,
|
||||
influxPort: (config.questdb as any).influxPort || (config.questdb as any).ilpPort || 9009,
|
||||
database: config.questdb.database || 'questdb',
|
||||
}
|
||||
: undefined;
|
||||
|
||||
return {
|
||||
redis: config.redis,
|
||||
|
|
@ -177,4 +211,4 @@ export class ServiceContainerBuilder {
|
|||
service: config.service,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue