import { Module } from '@nestjs/common'; import { ConfigModule, ConfigService } from '@nestjs/config'; import { BullModule } from '@nestjs/bullmq'; import { TerminusModule } from '@nestjs/terminus'; import { ThrottlerModule } from '@nestjs/throttler'; import { RedisModule } from '@nestjs-modules/ioredis'; // Import custom modules import { VisionModule } from './vision/vision.module'; import { ProcessorsModule } from './processors/processors.module'; import { StorageModule } from './storage/storage.module'; import { QueueModule } from './queue/queue.module'; import { MonitoringModule } from './monitoring/monitoring.module'; import { HealthModule } from './health/health.module'; // Import configuration import { validationSchema } from './config/validation.schema'; import { workerConfig } from './config/worker.config'; @Module({ imports: [ // Configuration module with environment validation ConfigModule.forRoot({ isGlobal: true, load: [workerConfig], validationSchema, validationOptions: { abortEarly: true, }, }), // Rate limiting ThrottlerModule.forRoot([{ ttl: 60000, // 1 minute limit: 100, // 100 requests per minute }]), // Redis connection for progress tracking RedisModule.forRootAsync({ imports: [ConfigModule], useFactory: (configService: ConfigService) => ({ type: 'single', url: configService.get('REDIS_URL', 'redis://localhost:6379'), options: { password: configService.get('REDIS_PASSWORD'), db: configService.get('REDIS_DB', 0), retryDelayOnFailover: 100, maxRetriesPerRequest: 3, }, }), inject: [ConfigService], }), // BullMQ Redis connection BullModule.forRootAsync({ imports: [ConfigModule], useFactory: async (configService: ConfigService) => ({ connection: { host: configService.get('REDIS_HOST', 'localhost'), port: configService.get('REDIS_PORT', 6379), password: configService.get('REDIS_PASSWORD'), db: configService.get('REDIS_DB', 0), retryDelayOnFailover: 100, enableReadyCheck: false, maxRetriesPerRequest: 3, }, defaultJobOptions: { removeOnComplete: 10, removeOnFail: 5, attempts: 3, backoff: { type: 'exponential', delay: 2000, }, }, }), inject: [ConfigService], }), // Register queues BullModule.registerQueue( { name: 'image-processing' }, { name: 'batch-processing' }, { name: 'virus-scan' }, { name: 'file-cleanup' }, ), // Health checks TerminusModule, // Core service modules VisionModule, ProcessorsModule, StorageModule, QueueModule, MonitoringModule, HealthModule, ], controllers: [], providers: [], }) export class AppModule { constructor(private configService: ConfigService) { this.logConfiguration(); } private logConfiguration() { const logger = require('@nestjs/common').Logger; const log = new logger('AppModule'); log.log('🔧 Worker Configuration:'); log.log(`• Environment: ${this.configService.get('NODE_ENV')}`); log.log(`• Worker Port: ${this.configService.get('WORKER_PORT')}`); log.log(`• Redis Host: ${this.configService.get('REDIS_HOST')}`); log.log(`• Max Concurrent Jobs: ${this.configService.get('MAX_CONCURRENT_JOBS')}`); log.log(`• OpenAI API Key: ${this.configService.get('OPENAI_API_KEY') ? '✓ Set' : '✗ Missing'}`); log.log(`• Google Vision Key: ${this.configService.get('GOOGLE_CLOUD_VISION_KEY') ? '✓ Set' : '✗ Missing'}`); log.log(`• MinIO Config: ${this.configService.get('MINIO_ENDPOINT') ? '✓ Set' : '✗ Missing'}`); } }