refactoring continuing

This commit is contained in:
Boki 2025-06-22 08:27:54 -04:00
parent 742e590382
commit a0a3b26177
20 changed files with 394 additions and 798 deletions

View file

@ -0,0 +1,85 @@
# Awilix DI Container Migration Guide
This guide explains how to use the new Awilix dependency injection container in the data-ingestion service.
## Overview
The Awilix container provides proper dependency injection for decoupled libraries, allowing them to be reused in other projects without stock-bot specific dependencies.
## Current Implementation
The data-ingestion service now uses a hybrid approach:
1. Awilix container for ProxyManager and other decoupled services
2. Legacy service factory for backward compatibility
## Usage Example
```typescript
// Create Awilix container
const awilixConfig = {
redis: {
host: config.database.dragonfly.host,
port: config.database.dragonfly.port,
db: config.database.dragonfly.db,
},
mongodb: {
uri: config.database.mongodb.uri,
database: config.database.mongodb.database,
},
postgres: {
host: config.database.postgres.host,
port: config.database.postgres.port,
database: config.database.postgres.database,
user: config.database.postgres.user,
password: config.database.postgres.password,
},
proxy: {
cachePrefix: 'proxy:',
ttl: 3600,
},
};
const container = createServiceContainer(awilixConfig);
await initializeServices(container);
// Access services from container
const proxyManager = container.resolve('proxyManager');
const cache = container.resolve('cache');
```
## Handler Integration
Handlers receive services through the enhanced service container:
```typescript
// Create service adapter with proxy from Awilix
const serviceContainerWithProxy = createServiceAdapter(services);
Object.defineProperty(serviceContainerWithProxy, 'proxy', {
get: () => container.resolve('proxyManager'),
enumerable: true,
configurable: true
});
// Handlers can now access proxy service
class MyHandler extends BaseHandler {
async myOperation() {
const proxy = this.proxy.getRandomProxy();
// Use proxy...
}
}
```
## Benefits
1. **Decoupled Libraries**: Libraries no longer depend on @stock-bot/config
2. **Reusability**: Libraries can be used in other projects
3. **Testability**: Easy to mock dependencies for testing
4. **Type Safety**: Full TypeScript support with Awilix
## Next Steps
To fully migrate to Awilix:
1. Update HTTP library to accept dependencies via constructor
2. Update Queue library to accept Redis config via constructor
3. Create actual MongoDB, PostgreSQL, and QuestDB clients in the container
4. Remove legacy service factory once all services are migrated

View file

@ -3,8 +3,7 @@
* Automatically discovers and registers all handlers
*/
import type { IDataIngestionServices } from '@stock-bot/di';
import { createServiceAdapter } from '@stock-bot/di';
import type { IServiceContainer } from '@stock-bot/handlers';
import { autoRegisterHandlers } from '@stock-bot/handlers';
import { getLogger } from '@stock-bot/logger';
import { join } from 'path';
@ -19,10 +18,7 @@ const logger = getLogger('handler-init');
/**
* Initialize and register all handlers automatically
*/
export async function initializeAllHandlers(services: IDataIngestionServices): Promise<void> {
// Create generic service container adapter
const serviceContainer = createServiceAdapter(services);
export async function initializeAllHandlers(serviceContainer: IServiceContainer): Promise<void> {
try {
// Auto-register all handlers in this directory
const result = await autoRegisterHandlers(

View file

@ -6,7 +6,6 @@ import {
type ExecutionContext,
type IServiceContainer
} from '@stock-bot/handlers';
import { updateProxies } from '@stock-bot/utils';
@Handler('webshare')
export class WebShareHandler extends BaseHandler {
@ -28,8 +27,8 @@ export class WebShareHandler extends BaseHandler {
const proxies = await fetchWebShareProxies();
if (proxies.length > 0) {
// Update the centralized proxy manager
await updateProxies(proxies);
// Update the centralized proxy manager using the injected service
await this.proxy.updateProxies(proxies);
this.logger.info('Updated proxy manager with WebShare proxies', {
count: proxies.length,

View file

@ -10,14 +10,17 @@ import { cors } from 'hono/cors';
// Library imports
import {
createServiceContainer,
initializeServices as initializeAwilixServices,
createServiceAdapter,
createDataIngestionServices,
disposeDataIngestionServices,
type IDataIngestionServices
type IDataIngestionServices,
type ServiceContainer
} from '@stock-bot/di';
import { getLogger, setLoggerConfig, shutdownLoggers } from '@stock-bot/logger';
import { Shutdown } from '@stock-bot/shutdown';
import { handlerRegistry } from '@stock-bot/types';
import { ProxyManager } from '@stock-bot/utils';
// Local imports
import { createRoutes } from './routes/create-routes';
@ -43,6 +46,7 @@ const logger = getLogger('data-ingestion');
const PORT = serviceConfig.port;
let server: ReturnType<typeof Bun.serve> | null = null;
let services: IDataIngestionServices | null = null;
let container: ServiceContainer | null = null;
let app: Hono | null = null;
// Initialize shutdown manager
@ -53,7 +57,36 @@ async function initializeServices() {
logger.info('Initializing data-ingestion service with improved DI...');
try {
// Create all services using the service factory
// Create Awilix container with proper config structure
logger.debug('Creating Awilix DI container...');
const awilixConfig = {
redis: {
host: config.database.dragonfly.host,
port: config.database.dragonfly.port,
db: config.database.dragonfly.db,
},
mongodb: {
uri: config.database.mongodb.uri,
database: config.database.mongodb.database,
},
postgres: {
host: config.database.postgres.host,
port: config.database.postgres.port,
database: config.database.postgres.database,
user: config.database.postgres.user,
password: config.database.postgres.password,
},
proxy: {
cachePrefix: 'proxy:',
ttl: 3600,
},
};
container = createServiceContainer(awilixConfig);
await initializeAwilixServices(container);
logger.info('Awilix container created and initialized');
// Create all services using the service factory (for backward compatibility)
logger.debug('Creating services using service factory...');
services = await createDataIngestionServices(config);
logger.info('All services created successfully');
@ -76,16 +109,20 @@ async function initializeServices() {
const routes = createRoutes(services);
app.route('/', routes);
// Initialize proxy manager
logger.debug('Initializing proxy manager...');
await ProxyManager.initialize();
logger.info('Proxy manager initialized');
// Initialize handlers with new DI pattern
logger.debug('Initializing data handlers with new DI pattern...');
// Initialize handlers with Awilix service container
logger.debug('Initializing data handlers with Awilix DI pattern...');
// Auto-register all handlers
await initializeAllHandlers(services);
// Create service adapter that includes proxy from Awilix container
const serviceContainerWithProxy = createServiceAdapter(services);
// Override the proxy service with the one from Awilix
Object.defineProperty(serviceContainerWithProxy, 'proxy', {
get: () => container!.resolve('proxyManager'),
enumerable: true,
configurable: true
});
// Auto-register all handlers with the enhanced service container
await initializeAllHandlers(serviceContainerWithProxy);
logger.info('Data handlers initialized with new DI pattern');