import { Injectable } from "@nestjs/common"; import { Interval } from "@nestjs/schedule"; import { ConfigService } from "@nestjs/config"; import { AppConfig } from "../config/app.config"; import { TraceLogger } from "../common/trace-logger"; import { SessionService } from "./session.service"; import { SessionContextService } from "./session-context.service"; /** * Periodically: * 1. Closes sessions that have been idle for longer than SESSION_IDLE_TIMEOUT_MINUTES. * 2. Deletes closed sessions whose updatedAt is older than SESSION_DELETE_CLOSED_DAYS. */ @Injectable() export class SessionSchedulerService { private readonly logger = new TraceLogger(SessionSchedulerService.name); constructor( private readonly sessionService: SessionService, private readonly sessionContextService: SessionContextService, private readonly config: ConfigService, ) {} @Interval(60_000) async runScheduler(): Promise { await this.closeExpired(); await this.deleteOldClosed(); } private async closeExpired(): Promise { const idleMinutes = this.config.get("SESSION_IDLE_TIMEOUT_MINUTES"); const cutoff = new Date(Date.now() - idleMinutes * 60_000); const expired = await this.sessionService.findExpiredOpen(cutoff); for (const session of expired) { await this.sessionContextService.close(session.sessionName); this.logger.log( `Session "${session.sessionName}" closed (idle > ${idleMinutes} min)`, ); } } private async deleteOldClosed(): Promise { const days = this.config.get("SESSION_DELETE_CLOSED_DAYS"); const cutoff = new Date(Date.now() - days * 86_400_000); const old = await this.sessionService.findOldClosed(cutoff); for (const session of old) { await this.sessionService.remove(session.id); this.logger.log( `Session "${session.sessionName}" deleted (closed > ${days} days ago)`, ); } } }