import { forwardRef, Inject, Module, Optional, type OnApplicationShutdown } from '@nestjs/common'; import { createQueue, type QueueHandle } from '@mosaicstack/queue'; import type { MosaicConfig } from '@mosaicstack/config'; import { MOSAIC_CONFIG } from '../config/config.module.js'; import { ChatModule } from '../chat/chat.module.js'; import { GCModule } from '../gc/gc.module.js'; import { ReloadModule } from '../reload/reload.module.js'; import { CommandExecutorService } from './command-executor.service.js'; import { CommandRegistryService } from './command-registry.service.js'; import { COMMANDS_REDIS } from './commands.tokens.js'; const COMMANDS_QUEUE_HANDLE = 'COMMANDS_QUEUE_HANDLE'; @Module({ imports: [GCModule, forwardRef(() => ReloadModule), forwardRef(() => ChatModule)], providers: [ { provide: COMMANDS_QUEUE_HANDLE, useFactory: (config: MosaicConfig | null): QueueHandle | null => { // On Local tier there is no Redis — skip the ioredis connection. // CommandExecutorService falls back to no-cache for /provider login on local. if (config?.queue?.type === 'local') return null; return createQueue(); }, inject: [MOSAIC_CONFIG], }, { provide: COMMANDS_REDIS, useFactory: (handle: QueueHandle | null) => handle?.redis ?? null, inject: [COMMANDS_QUEUE_HANDLE], }, CommandRegistryService, CommandExecutorService, ], exports: [CommandRegistryService, CommandExecutorService], }) export class CommandsModule implements OnApplicationShutdown { constructor( @Optional() @Inject(COMMANDS_QUEUE_HANDLE) private readonly handle: QueueHandle | null, ) {} async onApplicationShutdown(): Promise { await this.handle?.close().catch(() => {}); } }