sanket3280/code-execution
0
1/**2 * Startup Validation & Checks3 * Validates system configuration and dependencies on startup4 */5 6const logger = require('./logger');7const { config } = require('../config/env.config');8const { isConnected } = require('./database');9const { getCache } = require('./cache');10 11/**12 * Validate environment configuration13 */14const validateEnvironment = () => {15 // Silent validation16 17 const checks = {18 passed: [],19 warnings: [],20 failed: [],21 };22 23 // Check Node version24 const nodeVersion = process.version;25 const requiredVersion = 'v14.0.0';26 if (nodeVersion >= requiredVersion) {27 checks.passed.push(`Node.js version: ${nodeVersion}`);28 } else {29 checks.failed.push(`Node.js version ${nodeVersion} is below required ${requiredVersion}`);30 }31 32 // Check environment33 if (config.nodeEnv) {34 checks.passed.push(`Environment: ${config.nodeEnv}`);35 } else {36 checks.warnings.push('NODE_ENV not set, defaulting to development');37 }38 39 // Check JWT secret strength40 if (config.isProduction && config.jwt.secret.length < 32) {41 checks.failed.push('JWT_SECRET is too weak for production (minimum 32 characters)');42 } else {43 checks.passed.push('JWT secret configured');44 }45 46 // Check email configuration47 if (config.email.brevo.apiKey || config.email.gmail.user) {48 checks.passed.push('Email service configured');49 } else {50 checks.warnings.push('No email service configured');51 }52 53 // Check OAuth configuration54 if (config.oauth.google.enabled) {55 checks.passed.push('Google OAuth enabled');56 }57 if (config.oauth.github.enabled) {58 checks.passed.push('GitHub OAuth enabled');59 }60 if (!config.oauth.google.enabled && !config.oauth.github.enabled) {61 checks.warnings.push('No OAuth providers configured');62 }63 64 // Check Redis configuration65 if (config.redis.url) {66 checks.passed.push('Redis configured');67 } else {68 checks.warnings.push('Redis not configured, using memory cache');69 }70 71 return checks;72};73 74/**75 * Validate database connection76 */77const validateDatabase = async () => {78 logger.info('Validating database connection...');79 80 try {81 const connected = isConnected();82 83 if (!connected) {84 throw new Error('Database is not connected');85 }86 87 logger.success('Database connection validated');88 return { success: true, message: 'Database connected' };89 } catch (error) {90 logger.error('Database validation failed', error);91 return { success: false, message: error.message };92 }93};94 95/**96 * Validate cache system97 */98const validateCache = async () => {99 logger.info('Validating cache system...');100 101 try {102 const cache = getCache();103 104 // Test cache operations105 const testKey = 'startup_test';106 const testValue = { test: true, timestamp: Date.now() };107 108 await cache.set(testKey, testValue, 10);109 const retrieved = await cache.get(testKey);110 await cache.del(testKey);111 112 if (!retrieved || retrieved.test !== true) {113 throw new Error('Cache read/write test failed');114 }115 116 logger.success('Cache system validated');117 return { 118 success: true, 119 message: 'Cache operational',120 type: cache.useRedis ? 'Redis' : 'Memory',121 };122 } catch (error) {123 logger.error('Cache validation failed', error);124 return { success: false, message: error.message };125 }126};127 128/**129 * Check system resources130 */131const checkSystemResources = () => {132 logger.info('Checking system resources...');133 134 const memory = process.memoryUsage();135 const memoryUsageMB = Math.round(memory.heapUsed / 1024 / 1024);136 const memoryTotalMB = Math.round(memory.heapTotal / 1024 / 1024);137 const memoryPercentage = Math.round((memory.heapUsed / memory.heapTotal) * 100);138 139 const resources = {140 memory: {141 used: memoryUsageMB,142 total: memoryTotalMB,143 percentage: memoryPercentage,144 unit: 'MB',145 },146 uptime: process.uptime(),147 platform: process.platform,148 arch: process.arch,149 nodeVersion: process.version,150 };151 152 logger.info('System resources', resources);153 154 // Warn if memory usage is high155 if (memoryPercentage > 80) {156 logger.warn(`High memory usage: ${memoryPercentage}%`);157 }158 159 return resources;160};161 162/**163 * Run all startup checks164 */165const runStartupChecks = async () => {166 // Only show detailed checks in development167 if (config.isDevelopment) {168 logger.info('='.repeat(60));169 logger.info('๐ Running startup validation checks...');170 logger.info('='.repeat(60));171 }172 173 const results = {174 timestamp: new Date().toISOString(),175 environment: config.nodeEnv,176 port: config.port,177 checks: {},178 };179 180 // 1. Validate environment181 const envChecks = validateEnvironment();182 results.checks.environment = envChecks;183 184 // Log environment checks (only in development)185 if (config.isDevelopment) {186 if (envChecks.passed.length > 0) {187 logger.success(`Environment checks passed (${envChecks.passed.length}):`);188 envChecks.passed.forEach(check => logger.info(` โ ${check}`));189 }190 if (envChecks.warnings.length > 0) {191 logger.warn(`Environment warnings (${envChecks.warnings.length}):`);192 envChecks.warnings.forEach(warning => logger.warn(` โ ${warning}`));193 }194 }195 196 // Always show failures197 if (envChecks.failed.length > 0) {198 logger.error(`Environment checks failed (${envChecks.failed.length}):`);199 envChecks.failed.forEach(failure => logger.error(` โ ${failure}`));200 }201 202 // 2. Validate database203 results.checks.database = await validateDatabase();204 205 // 3. Validate cache (silent in production)206 if (config.isDevelopment) {207 results.checks.cache = await validateCache();208 } else {209 // Silent cache validation in production210 try {211 const cache = getCache();212 results.checks.cache = { success: true, type: cache.useRedis ? 'Redis' : 'Memory' };213 } catch (error) {214 results.checks.cache = { success: false, message: error.message };215 }216 }217 218 // 4. Check system resources (only in development)219 if (config.isDevelopment) {220 results.checks.resources = checkSystemResources();221 }222 223 // Summary224 if (config.isDevelopment) {225 logger.info('='.repeat(60));226 }227 228 const allPassed = 229 envChecks.failed.length === 0 &&230 results.checks.database.success &&231 results.checks.cache.success;232 233 if (allPassed) {234 logger.success('โ
All startup checks passed!');235 } else {236 logger.warn('โ ๏ธ Some startup checks failed or have warnings');237 }238 239 if (config.isDevelopment) {240 logger.info('='.repeat(60));241 }242 243 return results;244};245 246/**247 * Display startup banner248 */249const displayStartupBanner = () => {250 // Only show banner in development251 if (!config.isDevelopment) {252 console.log(`\n๐ CodeBattle API - ${config.nodeEnv.toUpperCase()} - v1.0.0\n`);253 return;254 }255 256 const banner = `257โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ258โ โ259โ โโโโโโโ โโโโโโโ โโโโโโโ โโโโโโโโโโโโโโโ โโโโโโ โโโโโโโโโโโโโโโโโโโโโ โโโโโโโโ260โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโ261โ โโโ โโโ โโโโโโ โโโโโโโโโ โโโโโโโโโโโโโโโโ โโโ โโโ โโโ โโโโโโ 262โ โโโ โโโ โโโโโโ โโโโโโโโโ โโโโโโโโโโโโโโโโ โโโ โโโ โโโ โโโโโโ 263โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โโโ โโโ โโโ โโโโโโโโโโโโโโโโ264โ โโโโโโโ โโโโโโโ โโโโโโโ โโโโโโโโโโโโโโโ โโโ โโโ โโโ โโโ โโโโโโโโโโโโโโโโ265โ โ266โ Coding Challenge Platform โ267โ Environment: ${config.nodeEnv.toUpperCase().padEnd(9)} โ268โ Version: v1.0.0 โ269โ โ270โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ271`;272 273 console.log(banner);274};275 276module.exports = {277 validateEnvironment,278 validateDatabase,279 validateCache,280 checkSystemResources,281 runStartupChecks,282 displayStartupBanner,283};284 