config changes to make it not async

This commit is contained in:
Boki 2025-06-20 20:05:05 -04:00
parent 24680e403d
commit 92d4b90987
5 changed files with 131 additions and 13 deletions

8
.env
View file

@ -164,3 +164,11 @@ TZ=UTC
APP_NAME="Stock Bot Platform" APP_NAME="Stock Bot Platform"
APP_VERSION=1.0.0 APP_VERSION=1.0.0
APP_DESCRIPTION="Advanced Stock Trading and Analysis Platform" 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

View file

@ -1,12 +1,8 @@
/**
* Data Service - Market data ingestion service
*/
// Framework imports // Framework imports
import { Hono } from 'hono'; import { Hono } from 'hono';
import { cors } from 'hono/cors'; import { cors } from 'hono/cors';
import { initializeConfigSync } from '@stock-bot/config';
// Library imports // Library imports
import { initializeServiceConfig } from '@stock-bot/config';
import { getLogger, setLoggerConfig, shutdownLoggers } from '@stock-bot/logger'; import { getLogger, setLoggerConfig, shutdownLoggers } from '@stock-bot/logger';
import { connectMongoDB } from '@stock-bot/mongodb-client'; import { connectMongoDB } from '@stock-bot/mongodb-client';
import { connectPostgreSQL } from '@stock-bot/postgres-client'; import { connectPostgreSQL } from '@stock-bot/postgres-client';
@ -16,17 +12,14 @@ import { ProxyManager } from '@stock-bot/utils';
// Local imports // Local imports
import { exchangeRoutes, healthRoutes, queueRoutes } from './routes'; import { exchangeRoutes, healthRoutes, queueRoutes } from './routes';
// Initialize configuration with automatic monorepo config inheritance const config = initializeConfigSync();
const config = await initializeServiceConfig();
const serviceConfig = config.service; const serviceConfig = config.service;
const databaseConfig = config.database; const databaseConfig = config.database;
const queueConfig = config.queue; const queueConfig = config.queue;
// Initialize logger with config if (config.log) {
const logConfig = config.log;
if (logConfig) {
setLoggerConfig({ setLoggerConfig({
logLevel: logConfig.level, logLevel: config.log.level,
logConsole: true, logConsole: true,
logFile: false, logFile: false,
environment: config.environment, environment: config.environment,
@ -101,9 +94,21 @@ async function initializeServices() {
// Initialize queue system // Initialize queue system
logger.debug('Initializing queue system...'); logger.debug('Initializing queue system...');
const queueManagerConfig: QueueManagerConfig = { const queueManagerConfig: QueueManagerConfig = {
redis: queueConfig.redis, redis: queueConfig?.redis || {
host: 'localhost',
port: 6379,
db: 1,
},
defaultQueueOptions: { defaultQueueOptions: {
defaultJobOptions: queueConfig.defaultJobOptions, defaultJobOptions: queueConfig?.defaultJobOptions || {
attempts: 3,
backoff: {
type: 'exponential',
delay: 1000,
},
removeOnComplete: true,
removeOnFail: false,
},
workers: 5, workers: 5,
concurrency: 20, concurrency: 20,
enableMetrics: true, enableMetrics: true,

View file

@ -82,6 +82,51 @@ export class ConfigManager<T = Record<string, unknown>> {
return this.config; 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<string, unknown>)['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 * Get the current configuration
*/ */

View file

@ -27,6 +27,62 @@ import { EnvLoader } from './loaders/env.loader';
// Create singleton instance // Create singleton instance
let configInstance: ConfigManager<AppConfig> | null = null; let configInstance: ConfigManager<AppConfig> | 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<AppConfig>({
loaders: [
new EnvLoader(''), // Environment variables only for sync
]
});
}
return configInstance.initializeSync(appConfigSchema);
}
/** /**
* Initialize the global configuration * Initialize the global configuration
*/ */

View file

@ -26,6 +26,10 @@ export class EnvLoader implements ConfigLoader {
} }
async load(): Promise<Record<string, unknown>> { async load(): Promise<Record<string, unknown>> {
return this.loadSync();
}
loadSync(): Record<string, unknown> {
try { try {
// Load root .env file - try multiple possible locations // Load root .env file - try multiple possible locations
const possiblePaths = ['./.env', '../.env', '../../.env']; const possiblePaths = ['./.env', '../.env', '../../.env'];