created a service container and moved all possible stuff to it to make light index files with reusable container
This commit is contained in:
parent
9a5e87ef4a
commit
eeb5d1aca2
7 changed files with 766 additions and 633 deletions
|
|
@ -1,183 +1,78 @@
|
|||
/**
|
||||
* Stock Bot Web API with Dependency Injection
|
||||
* REST API service using Awilix container for managing connections
|
||||
* Stock Bot Web API
|
||||
* Simplified entry point using ServiceApplication framework
|
||||
*/
|
||||
|
||||
// Framework imports
|
||||
import { Hono } from 'hono';
|
||||
import { cors } from 'hono/cors';
|
||||
import { initializeServiceConfig } from '@stock-bot/config';
|
||||
|
||||
// Library imports
|
||||
import {
|
||||
ServiceApplication,
|
||||
createServiceContainerFromConfig,
|
||||
initializeServices as initializeAwilixServices,
|
||||
type ServiceContainer
|
||||
} from '@stock-bot/di';
|
||||
import { getLogger, setLoggerConfig, shutdownLoggers } from '@stock-bot/logger';
|
||||
import { Shutdown } from '@stock-bot/shutdown';
|
||||
import { getLogger } from '@stock-bot/logger';
|
||||
|
||||
// Local imports
|
||||
import { createRoutes } from './routes/create-routes';
|
||||
import { setupServiceContainer } from './container-setup';
|
||||
|
||||
// Initialize configuration
|
||||
const config = initializeServiceConfig();
|
||||
console.log('Web API Service Configuration:', JSON.stringify(config, null, 2));
|
||||
const serviceConfig = config.service;
|
||||
|
||||
if (config.log) {
|
||||
setLoggerConfig({
|
||||
logLevel: config.log.level,
|
||||
logConsole: true,
|
||||
logFile: false,
|
||||
environment: config.environment,
|
||||
hideObject: config.log.hideObject,
|
||||
// Create service application
|
||||
const app = new ServiceApplication(
|
||||
config,
|
||||
{
|
||||
serviceName: 'web-api',
|
||||
enableHandlers: false, // Web API doesn't use handlers
|
||||
enableScheduledJobs: false, // Web API doesn't use scheduled jobs
|
||||
corsConfig: {
|
||||
origin: ['http://localhost:4200', 'http://localhost:3000', 'http://localhost:3002'],
|
||||
allowMethods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
|
||||
allowHeaders: ['Content-Type', 'Authorization'],
|
||||
credentials: true,
|
||||
},
|
||||
serviceMetadata: {
|
||||
version: '1.0.0',
|
||||
description: 'Stock Bot REST API',
|
||||
endpoints: {
|
||||
health: '/health',
|
||||
exchanges: '/api/exchanges',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// Custom lifecycle hooks
|
||||
onContainerReady: (container) => {
|
||||
// Setup service-specific configuration
|
||||
const enhancedContainer = setupServiceContainer(config, container);
|
||||
return enhancedContainer;
|
||||
},
|
||||
onStarted: (port) => {
|
||||
const logger = getLogger('web-api');
|
||||
logger.info('Web API service startup initiated with ServiceApplication framework');
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
// Container factory function
|
||||
async function createContainer(config: any) {
|
||||
const container = createServiceContainerFromConfig(config, {
|
||||
enableQuestDB: false, // Web API doesn't need QuestDB
|
||||
enableMongoDB: true,
|
||||
enablePostgres: true,
|
||||
enableCache: true,
|
||||
enableQueue: false, // Web API doesn't need queue processing
|
||||
enableBrowser: false, // Web API doesn't need browser
|
||||
enableProxy: false, // Web API doesn't need proxy
|
||||
});
|
||||
await initializeAwilixServices(container);
|
||||
return container;
|
||||
}
|
||||
|
||||
// Create logger AFTER config is set
|
||||
const logger = getLogger('web-api');
|
||||
|
||||
const PORT = serviceConfig.port;
|
||||
let server: ReturnType<typeof Bun.serve> | null = null;
|
||||
let container: ServiceContainer | null = null;
|
||||
let app: Hono | null = null;
|
||||
|
||||
// Initialize shutdown manager
|
||||
const shutdown = Shutdown.getInstance({ timeout: 15000 });
|
||||
|
||||
// Initialize services with DI pattern
|
||||
async function initializeServices() {
|
||||
logger.info('Initializing web API service with DI...');
|
||||
|
||||
try {
|
||||
// Create Awilix container directly from AppConfig
|
||||
logger.debug('Creating Awilix DI container...');
|
||||
container = createServiceContainerFromConfig(config, {
|
||||
enableQuestDB: false, // Web API doesn't need QuestDB
|
||||
enableMongoDB: true,
|
||||
enablePostgres: true,
|
||||
enableCache: true,
|
||||
enableQueue: false, // Web API doesn't need queue processing
|
||||
enableBrowser: false, // Web API doesn't need browser
|
||||
enableProxy: false, // Web API doesn't need proxy
|
||||
});
|
||||
await initializeAwilixServices(container);
|
||||
logger.info('Awilix container created and initialized');
|
||||
|
||||
// Setup service-specific configuration
|
||||
const serviceContainer = setupServiceContainer(config, container.resolve('serviceContainer'));
|
||||
|
||||
|
||||
// Create app with routes
|
||||
app = new Hono();
|
||||
|
||||
// Add CORS middleware
|
||||
app.use(
|
||||
'*',
|
||||
cors({
|
||||
origin: ['http://localhost:4200', 'http://localhost:3000', 'http://localhost:3002'],
|
||||
allowMethods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
|
||||
allowHeaders: ['Content-Type', 'Authorization'],
|
||||
credentials: true,
|
||||
})
|
||||
);
|
||||
|
||||
// Basic API info endpoint
|
||||
app.get('/', c => {
|
||||
return c.json({
|
||||
name: 'Stock Bot Web API',
|
||||
version: '1.0.0',
|
||||
status: 'running',
|
||||
timestamp: new Date().toISOString(),
|
||||
endpoints: {
|
||||
health: '/health',
|
||||
exchanges: '/api/exchanges',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
// Create and mount routes using the service container
|
||||
const routes = createRoutes(serviceContainer);
|
||||
app.route('/', routes);
|
||||
|
||||
logger.info('All services initialized successfully');
|
||||
} catch (error) {
|
||||
console.error('DETAILED ERROR:', error);
|
||||
logger.error('Failed to initialize services', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
details: JSON.stringify(error, null, 2)
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// Start server
|
||||
async function startServer() {
|
||||
await initializeServices();
|
||||
|
||||
if (!app) {
|
||||
throw new Error('App not initialized');
|
||||
}
|
||||
|
||||
server = Bun.serve({
|
||||
port: PORT,
|
||||
fetch: app.fetch,
|
||||
development: config.environment === 'development',
|
||||
});
|
||||
|
||||
logger.info(`Web API service started on port ${PORT}`);
|
||||
}
|
||||
|
||||
// Register shutdown handlers with priorities
|
||||
// Priority 1: HTTP Server (high priority)
|
||||
shutdown.onShutdownHigh(async () => {
|
||||
if (server) {
|
||||
logger.info('Stopping HTTP server...');
|
||||
try {
|
||||
server.stop();
|
||||
logger.info('HTTP server stopped');
|
||||
} catch (error) {
|
||||
logger.error('Error stopping HTTP server', { error });
|
||||
}
|
||||
}
|
||||
}, 'HTTP Server');
|
||||
|
||||
// Priority 2: Services and connections (medium priority)
|
||||
shutdown.onShutdownMedium(async () => {
|
||||
logger.info('Disposing services and connections...');
|
||||
try {
|
||||
if (container) {
|
||||
// Disconnect database clients
|
||||
const mongoClient = container.resolve('mongoClient');
|
||||
if (mongoClient?.disconnect) await mongoClient.disconnect();
|
||||
|
||||
const postgresClient = container.resolve('postgresClient');
|
||||
if (postgresClient?.disconnect) await postgresClient.disconnect();
|
||||
|
||||
logger.info('All services disposed successfully');
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Error disposing services', { error });
|
||||
}
|
||||
}, 'Services');
|
||||
|
||||
// Priority 3: Logger shutdown (lowest priority - runs last)
|
||||
shutdown.onShutdownLow(async () => {
|
||||
try {
|
||||
logger.info('Shutting down loggers...');
|
||||
await shutdownLoggers();
|
||||
// Don't log after shutdown
|
||||
} catch {
|
||||
// Silently ignore logger shutdown errors
|
||||
}
|
||||
}, 'Loggers');
|
||||
|
||||
// Start the service
|
||||
startServer().catch(error => {
|
||||
app.start(createContainer, createRoutes).catch(error => {
|
||||
const logger = getLogger('web-api');
|
||||
logger.fatal('Failed to start web API service', { error });
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
logger.info('Web API service startup initiated with DI pattern');
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue