From b86034108a8ac22d32fc1c8835a3df8443cc23f5 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sun, 4 Oct 2026 11:53:56 +0200 Subject: [PATCH] Feature/graceful shutdown (#8035) * Graceful shutdown of the server * Update changelog --- CHANGELOG.md | 6 ++++++ apps/api/src/main.ts | 9 +++++++++ apps/api/src/services/prisma/prisma.service.ts | 12 ++++++------ docker/docker-compose.yml | 1 + 4 files changed, 22 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6638c81f4d..a9ffe2149d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Extended the _Public API_ with the liveness probe endpoint (`GET api/v1/health/liveness`) (experimental) +- Added the graceful shutdown of the server on `SIGINT` and `SIGTERM` +- Added `stop_grace_period` to the _Ghostfolio_ service in the `docker-compose` file (`docker-compose.yml`) ### Changed @@ -21,6 +23,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed the asset profile of the activities after a fee, an interest or a liability with the same symbol in the activities import +### Todo + +- Add `stop_grace_period: 1m` to the _Ghostfolio_ service in your `docker-compose` file (see `docker-compose.yml`) + ## 3.78.0 - 2026-10-03 ### Added diff --git a/apps/api/src/main.ts b/apps/api/src/main.ts index 8b17cbca50..1282304c33 100644 --- a/apps/api/src/main.ts +++ b/apps/api/src/main.ts @@ -14,6 +14,7 @@ import { import { Logger, LogLevel, + ShutdownSignal, ValidationPipe, VersioningType } from '@nestjs/common'; @@ -65,6 +66,14 @@ async function bootstrap() { }); app.enableCors(); + + // Let the open requests and the active queue jobs finish on SIGINT and + // SIGTERM before the process stops. Exit explicitly because Linux ignores + // the re-raised signal if the process runs as PID 1 + app.enableShutdownHooks([ShutdownSignal.SIGINT, ShutdownSignal.SIGTERM], { + useProcessExit: true + }); + app.enableVersioning({ defaultVersion: '1', type: VersioningType.URI diff --git a/apps/api/src/services/prisma/prisma.service.ts b/apps/api/src/services/prisma/prisma.service.ts index df55e45f7c..fcf7c6e5ea 100644 --- a/apps/api/src/services/prisma/prisma.service.ts +++ b/apps/api/src/services/prisma/prisma.service.ts @@ -2,7 +2,7 @@ import { Injectable, Logger, LogLevel, - OnModuleDestroy, + OnApplicationShutdown, OnModuleInit } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; @@ -12,7 +12,7 @@ import { Prisma, PrismaClient } from '@prisma/client'; @Injectable() export class PrismaService extends PrismaClient - implements OnModuleInit, OnModuleDestroy + implements OnApplicationShutdown, OnModuleInit { private readonly logger = new Logger(PrismaService.name); @@ -41,6 +41,10 @@ export class PrismaService }); } + public async onApplicationShutdown() { + await this.$disconnect(); + } + public async onModuleInit() { try { await this.$connect(); @@ -48,8 +52,4 @@ export class PrismaService this.logger.error(error); } } - - public async onModuleDestroy() { - await this.$disconnect(); - } } diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 8c69e5420e..cf58ea0143 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -5,6 +5,7 @@ services: container_name: ghostfolio restart: unless-stopped init: true + stop_grace_period: 1m cap_drop: - ALL security_opt: