feat(gateway): SessionGCService three-tier GC + /gc command + cron (P8-014)
Implements three-tier garbage collection for agent sessions: - SessionGCService.collect() for immediate per-session cleanup on destroySession() - SessionGCService.sweepOrphans() for daily cron sweep of orphaned Valkey keys - SessionGCService.fullCollect() for cold-start aggressive cleanup via OnModuleInit - /gc slash command wired into CommandExecutorService + registered in CommandRegistryService - SESSION_GC_CRON (daily 4am) added to CronService - GCModule provides Valkey (ioredis via @mosaic/queue) and is imported by AgentModule, LogModule, CommandsModule, AppModule - 8 Vitest unit tests covering all three GC tiers Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -9,10 +9,11 @@ import { AgentConfigsController } from './agent-configs.controller.js';
|
||||
import { CoordModule } from '../coord/coord.module.js';
|
||||
import { McpClientModule } from '../mcp-client/mcp-client.module.js';
|
||||
import { SkillsModule } from '../skills/skills.module.js';
|
||||
import { GCModule } from '../gc/gc.module.js';
|
||||
|
||||
@Global()
|
||||
@Module({
|
||||
imports: [CoordModule, McpClientModule, SkillsModule],
|
||||
imports: [CoordModule, McpClientModule, SkillsModule, GCModule],
|
||||
providers: [ProviderService, RoutingService, SkillLoaderService, AgentService],
|
||||
controllers: [ProvidersController, SessionsController, AgentConfigsController],
|
||||
exports: [AgentService, ProviderService, RoutingService, SkillLoaderService],
|
||||
|
||||
@@ -26,6 +26,7 @@ import { createWebTools } from './tools/web-tools.js';
|
||||
import type { SessionInfoDto } from './session.dto.js';
|
||||
import { SystemOverrideService } from '../preferences/system-override.service.js';
|
||||
import { PreferencesService } from '../preferences/preferences.service.js';
|
||||
import { SessionGCService } from '../gc/session-gc.service.js';
|
||||
|
||||
export interface AgentSessionOptions {
|
||||
provider?: string;
|
||||
@@ -101,6 +102,7 @@ export class AgentService implements OnModuleDestroy {
|
||||
@Optional()
|
||||
@Inject(PreferencesService)
|
||||
private readonly preferencesService: PreferencesService | null,
|
||||
@Inject(SessionGCService) private readonly gc: SessionGCService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -430,6 +432,14 @@ export class AgentService implements OnModuleDestroy {
|
||||
session.listeners.clear();
|
||||
session.channels.clear();
|
||||
this.sessions.delete(sessionId);
|
||||
|
||||
// Run GC cleanup for this session (fire and forget, errors are logged)
|
||||
this.gc.collect(sessionId).catch((err: unknown) => {
|
||||
this.logger.error(
|
||||
`GC collect failed for session ${sessionId}`,
|
||||
err instanceof Error ? err.stack : String(err),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
async onModuleDestroy(): Promise<void> {
|
||||
|
||||
Reference in New Issue
Block a user