diff --git a/.env b/.env index f6804bf..cc6f623 100644 --- a/.env +++ b/.env @@ -164,3 +164,11 @@ TZ=UTC APP_NAME="Stock Bot Platform" APP_VERSION=1.0.0 APP_DESCRIPTION="Advanced Stock Trading and Analysis Platform" + +# PostgreSQL +DATABASE_POSTGRES_HOST=localhost +DATABASE_POSTGRES_PORT=5432 +DATABASE_POSTGRES_DATABASE=trading_bot +DATABASE_POSTGRES_USER=trading_user +DATABASE_POSTGRES_PASSWORD=trading_pass_dev +EOF < /dev/null diff --git a/apps/data-service/src/index.ts b/apps/data-service/src/index.ts index 944b161..21c40ce 100644 --- a/apps/data-service/src/index.ts +++ b/apps/data-service/src/index.ts @@ -1,12 +1,8 @@ -/** - * Data Service - Market data ingestion service - */ - // Framework imports import { Hono } from 'hono'; import { cors } from 'hono/cors'; +import { initializeConfigSync } from '@stock-bot/config'; // Library imports -import { initializeServiceConfig } from '@stock-bot/config'; import { getLogger, setLoggerConfig, shutdownLoggers } from '@stock-bot/logger'; import { connectMongoDB } from '@stock-bot/mongodb-client'; import { connectPostgreSQL } from '@stock-bot/postgres-client'; @@ -16,17 +12,14 @@ import { ProxyManager } from '@stock-bot/utils'; // Local imports import { exchangeRoutes, healthRoutes, queueRoutes } from './routes'; -// Initialize configuration with automatic monorepo config inheritance -const config = await initializeServiceConfig(); +const config = initializeConfigSync(); const serviceConfig = config.service; const databaseConfig = config.database; const queueConfig = config.queue; -// Initialize logger with config -const logConfig = config.log; -if (logConfig) { +if (config.log) { setLoggerConfig({ - logLevel: logConfig.level, + logLevel: config.log.level, logConsole: true, logFile: false, environment: config.environment, @@ -101,9 +94,21 @@ async function initializeServices() { // Initialize queue system logger.debug('Initializing queue system...'); const queueManagerConfig: QueueManagerConfig = { - redis: queueConfig.redis, + redis: queueConfig?.redis || { + host: 'localhost', + port: 6379, + db: 1, + }, defaultQueueOptions: { - defaultJobOptions: queueConfig.defaultJobOptions, + defaultJobOptions: queueConfig?.defaultJobOptions || { + attempts: 3, + backoff: { + type: 'exponential', + delay: 1000, + }, + removeOnComplete: true, + removeOnFail: false, + }, workers: 5, concurrency: 20, enableMetrics: true, diff --git a/libs/config/src/config-manager.ts b/libs/config/src/config-manager.ts index e904b27..e06d098 100644 --- a/libs/config/src/config-manager.ts +++ b/libs/config/src/config-manager.ts @@ -82,6 +82,51 @@ export class ConfigManager> { return this.config; } + /** + * Initialize the configuration synchronously (only env vars, no file loading) + */ + initializeSync(schema?: ConfigSchema): T { + if (this.config) { + return this.config; + } + + this.schema = schema; + + // Only use EnvLoader for sync initialization + const envLoader = this.loaders.find(loader => loader.constructor.name === 'EnvLoader'); + if (!envLoader) { + throw new ConfigError('No EnvLoader found for synchronous initialization'); + } + + // Load env vars synchronously + const envLoaderInstance = envLoader as any; + const config = envLoaderInstance.loadSync ? envLoaderInstance.loadSync() : {}; + + // Add environment if not present + if (typeof config === 'object' && config !== null && !('environment' in config)) { + (config as Record)['environment'] = this.environment; + } + + // Validate if schema provided + if (this.schema) { + try { + this.config = this.schema.parse(config) as T; + } catch (error) { + if (error instanceof z.ZodError) { + throw new ConfigValidationError( + 'Configuration validation failed', + error.errors + ); + } + throw error; + } + } else { + this.config = config as T; + } + + return this.config; + } + /** * Get the current configuration */ diff --git a/libs/config/src/index.ts b/libs/config/src/index.ts index 7001670..93ee4f5 100644 --- a/libs/config/src/index.ts +++ b/libs/config/src/index.ts @@ -27,6 +27,62 @@ import { EnvLoader } from './loaders/env.loader'; // Create singleton instance let configInstance: ConfigManager | null = null; +// Synchronously load critical env vars for early initialization +function loadCriticalEnvVarsSync(): void { + // Load .env file synchronously if it exists + try { + const fs = require('fs'); + const path = require('path'); + const envPath = path.resolve(process.cwd(), '.env'); + if (fs.existsSync(envPath)) { + const envContent = fs.readFileSync(envPath, 'utf-8'); + const lines = envContent.split('\n'); + + for (const line of lines) { + const trimmed = line.trim(); + if (!trimmed || trimmed.startsWith('#')) continue; + + const equalIndex = trimmed.indexOf('='); + if (equalIndex === -1) continue; + + const key = trimmed.substring(0, equalIndex).trim(); + let value = trimmed.substring(equalIndex + 1).trim(); + + // Remove surrounding quotes + if ((value.startsWith('"') && value.endsWith('"')) || + (value.startsWith("'") && value.endsWith("'"))) { + value = value.slice(1, -1); + } + + // Only set if not already set + if (!(key in process.env)) { + process.env[key] = value; + } + } + } + } catch (error) { + // Ignore errors - env file is optional + } +} + +// Load critical env vars immediately +loadCriticalEnvVarsSync(); + +/** + * Initialize configuration synchronously (env vars only) + * This should be called at the very start of the application + */ +export function initializeConfigSync(): AppConfig { + if (!configInstance) { + configInstance = new ConfigManager({ + loaders: [ + new EnvLoader(''), // Environment variables only for sync + ] + }); + } + return configInstance.initializeSync(appConfigSchema); +} + /** * Initialize the global configuration */ diff --git a/libs/config/src/loaders/env.loader.ts b/libs/config/src/loaders/env.loader.ts index 9ca82ec..7d444ce 100644 --- a/libs/config/src/loaders/env.loader.ts +++ b/libs/config/src/loaders/env.loader.ts @@ -26,6 +26,10 @@ export class EnvLoader implements ConfigLoader { } async load(): Promise> { + return this.loadSync(); + } + + loadSync(): Record { try { // Load root .env file - try multiple possible locations const possiblePaths = ['./.env', '../.env', '../../.env'];