diff --git a/src/redis/redis-manager/redis-manager.service.ts b/src/redis/redis-manager/redis-manager.service.ts index b3587f8..3bdc860 100644 --- a/src/redis/redis-manager/redis-manager.service.ts +++ b/src/redis/redis-manager/redis-manager.service.ts @@ -1,16 +1,18 @@ -import { Injectable, Logger } from "@nestjs/common"; +import { Injectable, Logger, OnApplicationShutdown } from "@nestjs/common"; import IORedis, { Redis, RedisOptions } from "ioredis"; import { ConfigService } from "@nestjs/config"; import { RedisConfig } from "../../configs/types/RedisConfig"; @Injectable() -export class RedisManagerService { +export class RedisManagerService implements OnApplicationShutdown { private config: RedisConfig; protected connections: { [key: string]: Redis; } = {}; + private healthCheckIntervals: ReturnType[] = []; + constructor( private readonly logger: Logger, private readonly configService: ConfigService, @@ -18,6 +20,22 @@ export class RedisManagerService { this.config = this.configService.get("redis")!; } + public async onApplicationShutdown() { + for (const interval of this.healthCheckIntervals) { + clearInterval(interval); + } + this.healthCheckIntervals = []; + + for (const [name, connection] of Object.entries(this.connections)) { + try { + connection.disconnect(); + } catch (error) { + this.logger.warn(`Error disconnecting Redis "${name}":`, error); + } + } + this.connections = {}; + } + public getConnection(connection = "default"): Redis { if (!this.connections[connection]) { const currentConnection: Redis = (this.connections[connection] = @@ -45,7 +63,7 @@ export class RedisManagerService { const pingTimeoutError = `did not receive ping in time (5 seconds)`; - setInterval(async () => { + const healthCheckInterval = setInterval(async () => { if (currentConnection.status === "ready") { await new Promise(async (resolve, reject) => { const timer = setTimeout(() => { @@ -65,6 +83,8 @@ export class RedisManagerService { }); } }, 5000); + + this.healthCheckIntervals.push(healthCheckInterval); }); } return this.connections[connection]; diff --git a/src/system/network.service.ts b/src/system/network.service.ts index 3631d01..3c0c212 100644 --- a/src/system/network.service.ts +++ b/src/system/network.service.ts @@ -1,12 +1,22 @@ import os from "os"; -import { spawn } from "child_process"; -import { Injectable, Logger, OnApplicationBootstrap } from "@nestjs/common"; +import { ChildProcess, spawn } from "child_process"; +import { + Injectable, + Logger, + OnApplicationBootstrap, + OnApplicationShutdown, +} from "@nestjs/common"; @Injectable() -export class NetworkService implements OnApplicationBootstrap { +export class NetworkService + implements OnApplicationBootstrap, OnApplicationShutdown +{ public publicIP: string; public networkLimit?: number; + private ipCheckInterval: ReturnType; + private spawnedProcesses = new Set(); + constructor(private readonly logger: Logger) {} public async getNetworkLimit() { @@ -24,7 +34,7 @@ export class NetworkService implements OnApplicationBootstrap { public async onApplicationBootstrap() { await this.getPublicIP(); - setInterval( + this.ipCheckInterval = setInterval( async () => { await this.getPublicIP(); }, @@ -32,6 +42,15 @@ export class NetworkService implements OnApplicationBootstrap { ); } + public async onApplicationShutdown() { + clearInterval(this.ipCheckInterval); + + for (const proc of this.spawnedProcesses) { + proc.kill(); + } + this.spawnedProcesses.clear(); + } + public getLanIP() { return this.getLanInterface().ipv4?.address; } @@ -305,16 +324,16 @@ export class NetworkService implements OnApplicationBootstrap { done`, ]); - process.on(process.env.DEV ? "SIGUSR2" : "SIGTERM", () => { - monitor.kill(); - }); + this.spawnedProcesses.add(monitor); monitor.stdin.on("error", async (error) => { this.logger.error("Error running processs", error); + monitor.kill(); reject(error); }); monitor.stderr.on("data", (error) => { + monitor.kill(); reject(error.toString()); }); @@ -327,6 +346,7 @@ export class NetworkService implements OnApplicationBootstrap { }); monitor.on("close", () => { + this.spawnedProcesses.delete(monitor); resolve( returnData || "No data written to memory due to onData() handler", ); diff --git a/src/utilities/throttle.ts b/src/utilities/throttle.ts index 3d1fc87..9e5b9a1 100644 --- a/src/utilities/throttle.ts +++ b/src/utilities/throttle.ts @@ -48,13 +48,14 @@ class Throttle { private totalBytes = 0; private isProcessing = false; private bytesPerSecond: number; + private intervalId: ReturnType; private queue: Array<{ chunk: Buffer; send: () => void; }> = []; constructor() { - setInterval(() => { + this.intervalId = setInterval(() => { this.totalBytes = 0; if (!this.isProcessing) { this.process(); @@ -62,6 +63,10 @@ class Throttle { }, 1000); } + public destroy() { + clearInterval(this.intervalId); + } + public setBytesPerSecond(bytesPerSecond: number) { if (this.bytesPerSecond !== bytesPerSecond) { this.bytesPerSecond = bytesPerSecond;