refactored di into more composable parts

This commit is contained in:
Boki 2025-06-22 21:47:39 -04:00
parent 177fe30586
commit 26ebc77fe6
22 changed files with 908 additions and 281 deletions

View file

@ -0,0 +1,96 @@
import type { AwilixContainer } from 'awilix';
import type { ServiceDefinitions } from '../container/types';
interface ServiceWithLifecycle {
connect?: () => Promise<void>;
disconnect?: () => Promise<void>;
close?: () => Promise<void>;
initialize?: () => Promise<void>;
shutdown?: () => Promise<void>;
}
export class ServiceLifecycleManager {
private readonly services = [
{ name: 'cache', key: 'cache' as const },
{ name: 'mongoClient', key: 'mongoClient' as const },
{ name: 'postgresClient', key: 'postgresClient' as const },
{ name: 'questdbClient', key: 'questdbClient' as const },
{ name: 'queueManager', key: 'queueManager' as const },
];
async initializeServices(
container: AwilixContainer<ServiceDefinitions>,
timeout = 30000
): Promise<void> {
const initPromises: Promise<void>[] = [];
for (const { name, key } of this.services) {
const service = container.cradle[key] as ServiceWithLifecycle | null;
if (service) {
const initPromise = this.initializeService(name, service);
initPromises.push(
Promise.race([
initPromise,
this.createTimeoutPromise(timeout, `${name} initialization timed out after ${timeout}ms`),
])
);
}
}
await Promise.all(initPromises);
console.log('✅ All services initialized successfully');
}
async shutdownServices(container: AwilixContainer<ServiceDefinitions>): Promise<void> {
const shutdownPromises: Promise<void>[] = [];
// Shutdown in reverse order
for (const { name, key } of [...this.services].reverse()) {
const service = container.cradle[key] as ServiceWithLifecycle | null;
if (service) {
shutdownPromises.push(this.shutdownService(name, service));
}
}
await Promise.allSettled(shutdownPromises);
console.log('✅ All services shut down');
}
private async initializeService(name: string, service: ServiceWithLifecycle): Promise<void> {
try {
if (typeof service.connect === 'function') {
await service.connect();
console.log(`${name} connected`);
} else if (typeof service.initialize === 'function') {
await service.initialize();
console.log(`${name} initialized`);
}
} catch (error) {
console.error(`❌ Failed to initialize ${name}:`, error);
throw error;
}
}
private async shutdownService(name: string, service: ServiceWithLifecycle): Promise<void> {
try {
if (typeof service.disconnect === 'function') {
await service.disconnect();
} else if (typeof service.close === 'function') {
await service.close();
} else if (typeof service.shutdown === 'function') {
await service.shutdown();
}
console.log(`${name} shut down`);
} catch (error) {
console.error(`❌ Error shutting down ${name}:`, error);
}
}
private createTimeoutPromise(timeout: number, message: string): Promise<never> {
return new Promise((_, reject) => {
setTimeout(() => reject(new Error(message)), timeout);
});
}
}