### Minimal Fastify Graceful Shutdown Setup Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/usage-examples.md A basic example showing how to register the plugin and define a simple shutdown handler. ```javascript const Fastify = require('fastify') const fastifyGracefulShutdown = require('fastify-graceful-shutdown') const fastify = Fastify() fastify.register(fastifyGracefulShutdown) fastify.after(() => { fastify.gracefulShutdown(async (signal) => { fastify.log.info(`Received ${signal}, shutting down gracefully`) }) }) fastify.listen({ port: 3000 }, (err, address) => { if (err) throw err fastify.log.info(`Server listening on ${address}`) }) ``` -------------------------------- ### Complete Production Setup with Fastify Graceful Shutdown Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/usage-examples.md This example shows a full production setup including service initialization (database, cache), extended graceful shutdown timeout, and custom cleanup logic for each service. It's suitable for applications requiring robust shutdown procedures. ```javascript const Fastify = require('fastify') const fastifyGracefulShutdown = require('fastify-graceful-shutdown') const DatabasePool = require('./database') const CacheService = require('./cache') const fastify = Fastify({ logger: { level: process.env.LOG_LEVEL || 'info', transport: { target: 'pino-pretty', options: { colorize: true, translateTime: 'SYS:standard', ignore: 'pid,hostname' } } } }) // Initialize services const db = new DatabasePool({ url: process.env.DATABASE_URL, maxConnections: 10 }) const cache = new CacheService({ url: process.env.REDIS_URL }) // Register graceful shutdown with extended timeout fastify.register(fastifyGracefulShutdown, { timeout: 30000, resetHandlersOnInit: process.env.NODE_ENV === 'test' }) // Register services fastify.register(async (fastify) => { await db.initialize() await cache.connect() fastify.log.info('All services initialized') // Add cleanup hooks for each service fastify.addHook('onClose', async () => { fastify.log.info('Server closed') }) }) // Main graceful shutdown handler fastify.after(() => { fastify.gracefulShutdown(async (signal) => { fastify.log.info({ signal }, 'Starting graceful shutdown') const cleanupStartTime = Date.now() try { // Database cleanup fastify.log.debug('Draining database connections') await Promise.race([ db.drain(), new Promise((_, reject) => setTimeout(() => reject(new Error('Database drain timeout')), 10000) ) ]) fastify.log.debug('Database drained successfully') } catch (err) { fastify.log.error({ err }, 'Database cleanup failed') // Continue with other cleanups } try { // Cache cleanup fastify.log.debug('Disconnecting cache') await Promise.race([ cache.disconnect(), new Promise((_, reject) => setTimeout(() => reject(new Error('Cache disconnect timeout')), 5000) ) ]) fastify.log.debug('Cache disconnected successfully') } catch (err) { fastify.log.error({ err }, 'Cache cleanup failed') } const duration = Date.now() - cleanupStartTime fastify.log.info({ duration: `${duration}ms` }, 'Graceful shutdown completed') }) }) // Routes fastify.get('/health', async (request, reply) => { return { status: 'ok' } }) fastify.get('/data', async (request, reply) => { const data = await db.query('SELECT * FROM data') return data }) fastify.post('/cache/:key', async (request, reply) => { await cache.set(request.params.key, request.body) return { cached: true } }) // Error handler fastify.setErrorHandler((error, request, reply) => { fastify.log.error({ err: error }, 'Unhandled error') reply.status(500).send({ error: 'Internal Server Error' }) }) // Start server const start = async () => { try { const address = await fastify.listen({ port: process.env.PORT || 3000 }) fastify.log.info(`Server listening at ${address}`) } catch (err) { fastify.log.error({ err }, 'Failed to start server') process.exit(1) } } start() ``` -------------------------------- ### Install fastify-graceful-shutdown Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/README.md Install the plugin using npm. ```bash npm install --save fastify-graceful-shutdown ``` -------------------------------- ### Manual Testing with Signals Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/usage-examples.md Demonstrates how to manually test the graceful shutdown functionality by starting a server and then sending termination signals (SIGTERM or SIGINT) from another terminal or by interrupting the process. ```bash # Start the server node app.js # In another terminal, send SIGTERM kill -SIGTERM # Or send SIGINT (Ctrl+C in terminal) # Ctrl+C in the first terminal ``` -------------------------------- ### Example Usage - Fastify Graceful Shutdown Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/api-reference-plugin.md Demonstrates how to register the fastify-graceful-shutdown plugin and then use the `gracefulShutdown` method to register cleanup handlers after the plugin is ready. Multiple handlers can be registered and will execute in parallel. ```javascript const Fastify = require('fastify') const fastifyGracefulShutdown = require('fastify-graceful-shutdown') const fastify = Fastify() // Register the plugin fastify.register(fastifyGracefulShutdown) // After plugin is ready, register shutdown handlers fastify.after(() => { // Register a single handler fastify.gracefulShutdown(async (signal) => { fastify.log.info({ signal }, 'Shutting down gracefully') // Close database connections, cleanup resources, etc. }) // Register multiple handlers - they will execute in parallel fastify.gracefulShutdown(async (signal) => { fastify.log.info('Closing database connection') // await db.close() }) }) // Start the server fastify.listen({ port: 3000 }, (err, address) => { if (err) throw err fastify.log.info(`Server listening on ${address}`) }) ``` -------------------------------- ### Dependency Injection for Event Listeners Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/architecture.md This example shows dependency injection for the `handlerEventListener` option. It defaults to `process` if no custom event source is provided, allowing for custom event sources, particularly for testing. ```javascript const handlerEventListener = opts.handlerEventListener || process ``` -------------------------------- ### Complete Shutdown Handling Pattern with Error Recovery Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/errors.md This comprehensive example illustrates a complete shutdown handling pattern. It includes configuring an adequate timeout, resetting handlers on init, and registering multiple graceful shutdown handlers with robust error handling for critical operations like database closure and cache clearing. ```javascript const Fastify = require('fastify') const fastifyGracefulShutdown = require('fastify-graceful-shutdown') const fastify = Fastify() // Configure with adequate timeout fastify.register(fastifyGracefulShutdown, { timeout: 30000, resetHandlersOnInit: true }) fastify.after(() => { // Register handlers with proper error handling fastify.gracefulShutdown(async (signal) => { fastify.log.info({ signal }, 'Beginning graceful shutdown') try { // Close database with timeout protection await Promise.race([ database.close(), new Promise((_, reject) => setTimeout(() => reject(new Error('Database close timeout')), 5000) ) ]) fastify.log.info('Database closed successfully') } catch (err) { fastify.log.error({ err }, 'Database close failed, continuing shutdown') } try { // Close other resources await cache.clear() fastify.log.info('Cache cleared') } catch (err) { fastify.log.error({ err }, 'Cache clear failed, continuing shutdown') } }) // Register additional handlers for other resources fastify.gracefulShutdown(async (signal) => { try { await externalService.disconnect() } catch (err) { fastify.log.error({ err }, 'Service disconnect failed') } }) }) fastify.listen({ port: 3000 }, (err, address) => { if (err) throw err fastify.log.info(`Server listening on ${address}`) }) ``` -------------------------------- ### Configure Fastify for Graceful Shutdown Tests Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/configuration.md Sets up a Fastify instance with the graceful shutdown plugin for integration tests. It uses a mock event listener and a shorter timeout for faster test execution. Ensure 'fastify-graceful-shutdown' is installed. ```javascript const Fastify = require('fastify') const fastifyGracefulShutdown = require('fastify-graceful-shutdown') const { EventEmitter } = require('events') // Create test fixture async function createTestFastify() { const fastify = Fastify() const mockEventListener = new EventEmitter() mockEventListener.exit = (code) => { /* do nothing */ } fastify.register(fastifyGracefulShutdown, { resetHandlersOnInit: true, handlerEventListener: mockEventListener, timeout: 5000 // Shorter timeout for tests }) return fastify } // Usage in test it('should register shutdown handler', async () => { const fastify = await createTestFastify() let shutdownCalled = false fastify.after(() => { fastify.gracefulShutdown(async (signal) => { shutdownCalled = true }) }) await fastify.ready() // Handler registration complete await fastify.close() }) ``` -------------------------------- ### Container/Kubernetes Deployment with Fastify Graceful Shutdown Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/usage-examples.md This example is tailored for Docker/Kubernetes environments where graceful shutdown is critical. It configures a shorter timeout to align with typical Kubernetes termination grace periods and includes a health check endpoint that reflects the service's readiness for shutdown. ```javascript const Fastify = require('fastify') const fastifyGracefulShutdown = require('fastify-graceful-shutdown') const fastify = Fastify({ logger: { level: 'info' } }) // Kubernetes allows ~30 seconds for graceful shutdown by default fastify.register(fastifyGracefulShutdown, { timeout: 25000 // Leave 5 seconds for process teardown }) fastify.register(async (fastify) => { // Initialize services await initializeDatabase() await initializeCache() }) fastify.after(() => { fastify.gracefulShutdown(async (signal) => { // Implement liveness probe response changes fastify.isHealthy = false fastify.log.info(`Received ${signal}, beginning graceful shutdown`) // Allow in-flight requests to complete await new Promise(resolve => setTimeout(resolve, 2000)) // Close database connections await Promise.all([ closeDatabase(), closeCache(), flushMetrics() ]) fastify.log.info('Graceful shutdown complete') }) }) fastify.get('/healthz', async () => { if (!fastify.isHealthy) { throw new Error('Service not healthy') } return { status: 'ok' } }) fastify.listen({ port: 3000, host: '0.0.0.0' }) ``` -------------------------------- ### Quick Start with Fastify Graceful Shutdown Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/reference.md Register the plugin and define a graceful shutdown handler. The handler will be called when the application receives a shutdown signal. ```javascript const Fastify = require('fastify') const fastifyGracefulShutdown = require('fastify-graceful-shutdown') const fastify = Fastify() fastify.register(fastifyGracefulShutdown) fastify.after(() => { fastify.gracefulShutdown(async (signal) => { fastify.log.info('Shutting down gracefully') }) }) fastify.listen({ port: 3000 }) ``` -------------------------------- ### Test Custom Event Listener for Graceful Shutdown Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/usage-examples.md This example shows how to test the graceful shutdown handler by providing a custom event listener. It simulates a 'SIGTERM' signal and verifies that the shutdown handler is called. ```javascript const Fastify = require('fastify') const fastifyGracefulShutdown = require('fastify-graceful-shutdown') const { EventEmitter } = require('events') const { expect } = require('chai') describe('Graceful Shutdown', () => { it('should call shutdown handler on signal', async () => { const fastify = Fastify() // Create mock event listener const mockEventListener = new EventEmitter() let exitCode = null mockEventListener.exit = (code) => { exitCode = code } let handlerCalled = false fastify.register(fastifyGracefulShutdown, { handlerEventListener: mockEventListener }) fastify.after(() => { fastify.gracefulShutdown(async (signal) => { handlerCalled = true expect(signal).to.equal('SIGTERM') }) }) await fastify.ready() // Simulate SIGTERM mockEventListener.emit('SIGTERM') // Give async handler time to complete await new Promise(resolve => setTimeout(resolve, 100)) expect(handlerCalled).to.be.true expect(exitCode).to.equal(0) await fastify.close() }) }) ``` -------------------------------- ### Testing Timeout Behavior Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/usage-examples.md Configures fastify-graceful-shutdown with a specific timeout and registers a cleanup handler that exceeds this timeout. This example is useful for verifying that the plugin correctly enforces the configured shutdown timeout and logs the expected error message. ```javascript const Fastify = require('fastify') const fastifyGracefulShutdown = require('fastify-graceful-shutdown') const fastify = Fastify() fastify.register(fastifyGracefulShutdown, { timeout: 3000 // 3 second timeout for testing }) fastify.after(() => { fastify.gracefulShutdown(async (signal) => { // This handler takes 5 seconds, longer than 3 second timeout await new Promise(resolve => setTimeout(resolve, 5000)) }) }) fastify.listen({ port: 3000 }) // Send SIGTERM and observe process exits after 3 seconds // Error will be logged: "Terminate process after timeout" ``` -------------------------------- ### Test Isolated Signal Handlers with Multiple Fastify Instances Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/usage-examples.md This example demonstrates how to test that signal handlers are isolated between multiple Fastify instances when `resetHandlersOnInit` is enabled. Each instance registers its own shutdown handler. ```javascript const Fastify = require('fastify') const fastifyGracefulShutdown = require('fastify-graceful-shutdown') describe('Multiple Fastify Instances', () => { it('should isolate signal handlers with resetHandlersOnInit', async () => { const fastify1 = Fastify() fastify1.register(fastifyGracefulShutdown, { resetHandlersOnInit: true }) const shutdownLog1 = [] fastify1.after(() => { fastify1.gracefulShutdown(async (signal) => { shutdownLog1.push('instance1') }) }) await fastify1.ready() await fastify1.close() const fastify2 = Fastify() fastify2.register(fastifyGracefulShutdown, { resetHandlersOnInit: true }) const shutdownLog2 = [] fastify2.after(() => { fastify2.gracefulShutdown(async (signal) => { shutdownLog2.push('instance2') }) }) await fastify2.ready() await fastify2.close() // Both instances were properly registered and cleaned up }) }) ``` -------------------------------- ### Timeout Protection Flow Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/README.md Details the process of timeout protection, showing when the timer starts and what happens if handlers do not complete within the specified timeout. ```text Handler starts ↓ [Timeout timer begins] ↓ [If handlers don't complete before timeout...] ↓ [Process exits with code 1] ``` -------------------------------- ### Run Tests with npm Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/reference.md Execute the test suite for the project using npm. Tests are performed using Mocha, Chai, and tsd. ```bash npm test ``` -------------------------------- ### Handler Execution Failure During Shutdown Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/errors.md When a shutdown handler throws an error or rejects a promise, the error is logged, and the process exits with code 1. This example demonstrates a handler failing during database closure. ```javascript fastify.after(() => { fastify.gracefulShutdown(async (signal) => { throw new Error('Database close failed') // This will trigger error exit }) }) ``` -------------------------------- ### Plugin Registration and Options Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/api-reference-plugin.md Details on how to register the fastify-graceful-shutdown plugin and its available configuration options. ```APIDOC ## Plugin Registration ### Module Path `index.js` (main entry point via `fastify-graceful-shutdown`) ### Plugin Metadata - **Name:** `fastify-graceful-shutdown` - **Fastify Compatibility:** `>=5.0.0` - **Type:** Plugin using `fastify-plugin` ## Plugin Function ```typescript fastifyGracefulShutdown( fastify: FastifyInstance, opts: fastifyGracefulShutdownOptions, next: () => void ): void ``` ### Parameters | Parameter | Type | Required | Default | Description | |-----------|------|----------|---------|-------------| | fastify | FastifyInstance | Yes | — | The Fastify instance to decorate | | opts | fastifyGracefulShutdownOptions | Yes | `{}` | Configuration options for the plugin | | next | Function | Yes | — | Callback to signal plugin registration completion | ### Plugin Options The `opts` parameter is an object with the following structure: | Option | Type | Required | Default | Description | |--------|------|----------|---------|-------------| | timeout | number | No | `10000` | Maximum time in milliseconds to wait for graceful shutdown before forcibly terminating the process | | resetHandlersOnInit | boolean | No | `false` | If `true`, removes any pre-existing signal handlers from a previous plugin instance before registering new ones | | handlerEventListener | EventEmitter & { exit(code?: number): never } | No | `process` | Custom event emitter to use for signal handling. Defaults to Node.js `process` object. Useful for testing or custom signal handling | ### Behavior 1. Creates a child logger from Fastify's logger with the label `plugin: 'fastify-graceful-shutdown'` 2. Registers listeners for `SIGINT` and `SIGTERM` signals 3. Warns if signal handlers already exist on the event listener 4. Optionally removes pre-existing handlers if `resetHandlersOnInit` is true 5. Decorates the Fastify instance with the `gracefulShutdown()` method ### Signal Handler Flow When a signal is received: 1. Log the signal at debug level 2. Start a timeout (default 10 seconds) that will force exit if shutdown is not complete 3. Invoke all registered shutdown handlers in parallel 4. Close the Fastify server 5. Flush the logger 6. Exit the process with code 0 on success or 1 on error ``` -------------------------------- ### Require Fastify Graceful Shutdown Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/INDEX.md Import the plugin using require. This is the main entry point for the plugin. ```javascript const fastifyGracefulShutdown = require('fastify-graceful-shutdown') ``` -------------------------------- ### Handle Multiple Instances Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/reference.md Register the plugin with the option to reset handlers during initialization, useful for scenarios with multiple plugin instances. ```javascript fastify.register(fastifyGracefulShutdown, { resetHandlersOnInit: true }) ``` -------------------------------- ### Timeout During Shutdown Handler Execution Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/errors.md If a shutdown handler exceeds the configured timeout (default 10 seconds), the process will exit with code 1 after logging a timeout error. This example shows a handler intentionally taking longer than the default timeout. ```javascript fastify.after(() => { fastify.gracefulShutdown(async (signal) => { // This handler takes 15 seconds with default 10 second timeout await new Promise(resolve => setTimeout(resolve, 15000)) }) }) // When signaled: // - After 10 seconds, error is logged // - Process exits with code 1 // - Handler is interrupted mid-execution ``` -------------------------------- ### FastifyInstance Decoration Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/types.md The plugin extends the Fastify instance interface by adding a `gracefulShutdown()` method, allowing direct registration of shutdown handlers. ```APIDOC ## FastifyInstance Decoration ### Description The plugin extends the Fastify instance interface by adding a `gracefulShutdown()` method, allowing direct registration of shutdown handlers. ### Type Definition ```typescript declare module 'fastify' { interface FastifyInstance { gracefulShutdown( handler: (signal: string) => Promise | void, ): void } } ``` This adds a `gracefulShutdown()` method to every Fastify instance after the plugin is registered. ``` -------------------------------- ### Registering Plugin with Default Configuration Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/configuration.md Register the plugin without any options to use its default configuration. The default timeout is 10000ms, resetHandlersOnInit is false, and the handler event listener is the process object. ```javascript fastify.register(fastifyGracefulShutdown) // Equivalent to: // fastify.register(fastifyGracefulShutdown, { // timeout: 10000, // resetHandlersOnInit: false, // handlerEventListener: process // }) ``` -------------------------------- ### Registering fastify-graceful-shutdown with Default and Custom Options Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/types.md Demonstrates how to register the fastify-graceful-shutdown plugin with default options, custom timeout and resetHandlersOnInit values, or a custom event listener. ```typescript import Fastify from 'fastify' import fastifyGracefulShutdown from 'fastify-graceful-shutdown' const fastify = Fastify() // With default options fastify.register(fastifyGracefulShutdown) // With custom options fastify.register(fastifyGracefulShutdown, { timeout: 30000, resetHandlersOnInit: true }) // With custom event listener fastify.register(fastifyGracefulShutdown, { handlerEventListener: customEventEmitter }) ``` -------------------------------- ### Format Code with npm Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/reference.md Check and format the project's code using Prettier. The configuration uses semi-colons disabled and single quotes enabled. ```bash npm run format ``` -------------------------------- ### Typical Shutdown Flow Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/INDEX.md Illustrates the sequence of events during a graceful shutdown process initiated by a signal. ```markdown Application starts ↓ Register shutdown handlers via fastify.gracefulShutdown() ↓ Process receives SIGINT/SIGTERM signal ↓ Plugin executes all registered handlers in parallel ↓ Fastify server closes ↓ Logger flushes ↓ Process exits with code 0 (success) or 1 (error) ``` -------------------------------- ### Optional Chaining for Logger Methods Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/reference.md Demonstrates the use of optional chaining for logger methods to ensure graceful degradation. This allows the plugin to function even if Fastify is initialized with logger: false. ```js logger.debug?.({ signal }, 'Received signal') ``` ```js logger.error?.({ err }, 'Process terminated') ``` ```js logger.flush?.() ``` -------------------------------- ### Export Fastify Plugin with fastify-plugin Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/architecture.md The main entry point exports a Fastify plugin wrapped with fastify-plugin for proper lifecycle management. ```javascript module.exports = fp(fastifyGracefulShutdown, { fastify: '>=5.0.0', name: 'fastify-graceful-shutdown', }) ``` -------------------------------- ### Creating a Child Logger for the Plugin Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/configuration.md Create a child logger instance from the Fastify logger to be used by the graceful shutdown plugin. This requires the Fastify logger to be a Pino logger that supports the .child() method. ```javascript const logger = fastify.log.child({ plugin: 'fastify-graceful-shutdown' }) ``` -------------------------------- ### Register Plugin with Default Options Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/README.md Register the fastify-graceful-shutdown plugin with Fastify using default options. ```javascript const fastifyGracefulShutdown = require('fastify-graceful-shutdown') // FastifyPluginCallback fastify.register(fastifyGracefulShutdown) ``` -------------------------------- ### Combined Configuration Options Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/configuration.md Combine multiple configuration options, such as `timeout`, `resetHandlersOnInit`, and `handlerEventListener`, for a customized graceful shutdown behavior. ```javascript const fastify = Fastify() fastify.register(fastifyGracefulShutdown, { timeout: 20000, resetHandlersOnInit: true, handlerEventListener: customEventEmitter }) fastify.after(() => { fastify.gracefulShutdown(async (signal) => { // Handler with 20 second timeout, reset handlers enabled }) }) ``` -------------------------------- ### PostgreSQL Connection Cleanup with Graceful Shutdown Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/usage-examples.md Shows how to manage PostgreSQL connection cleanup during graceful shutdown. Configures a longer timeout for the shutdown process to allow for database operations. ```javascript const Fastify = require('fastify') const fastifyGracefulShutdown = require('fastify-graceful-shutdown') const { Pool } = require('pg') const fastify = Fastify() const pool = new Pool({ connectionString: process.env.DATABASE_URL }) fastify.register(fastifyGracefulShutdown, { timeout: 15000 // Database cleanup might take longer }) fastify.after(() => { fastify.gracefulShutdown(async (signal) => { fastify.log.info(`Shutting down due to ${signal}`) try { fastify.log.info('Closing database connections') await pool.end() fastify.log.info('Database connections closed') } catch (err) { fastify.log.error({ err }, 'Failed to close database connections') throw err } }) }) fastify.get('/users', async (request, reply) => { const result = await pool.query('SELECT * FROM users') return result.rows }) fastify.listen({ port: 3000 }, (err) => { if (err) throw err fastify.log.info('Server started') }) ``` -------------------------------- ### Fastify Graceful Shutdown with Route Handler Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/usage-examples.md Demonstrates integrating graceful shutdown with a basic route handler. The shutdown handler logs a message indicating the server is shutting down. ```javascript const Fastify = require('fastify') const fastifyGracefulShutdown = require('fastify-graceful-shutdown') const fastify = Fastify() fastify.register(fastifyGracefulShutdown) fastify.get('/', async (request, reply) => { return { message: 'Hello World' } }) fastify.after(() => { fastify.gracefulShutdown(async (signal) => { fastify.log.info(`Server shutting down due to ${signal}`) }) }) fastify.listen({ port: 3000 }, (err, address) => { if (err) throw err fastify.log.info(`Server ready at ${address}`) }) // Gracefully handles Ctrl+C or kill signals ``` -------------------------------- ### Handling Pre-existing Signal Handlers Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/errors.md This snippet demonstrates the warning logged when a signal handler is already registered before the plugin initializes. It shows how to register the plugin afterward and the resulting behavior where both handlers fire. ```javascript // Signal handler registered externally process.on('SIGINT', () => { console.log('External handler') }) // Plugin registered afterward fastify.register(fastifyGracefulShutdown) // Warning logged: SIGINT handler was already registered ``` -------------------------------- ### Register fastify-graceful-shutdown Plugin Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/README.md Register the plugin with your Fastify instance. ```javascript fastify.register(require('fastify-graceful-shutdown')) ``` -------------------------------- ### Register Default Plugin Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/reference.md Register the plugin with its default settings. ```javascript fastify.register(fastifyGracefulShutdown) ``` -------------------------------- ### Handle Multiple Plugin Instances Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/README.md Enables the registration of multiple instances of the fastify-graceful-shutdown plugin. When set to true, handlers from previous instances are reset before new ones are added. ```javascript fastify.register(require('fastify-graceful-shutdown'), { resetHandlersOnInit: true }) ``` -------------------------------- ### Conditional Logger Initialization Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/architecture.md This snippet shows how to conditionally initialize a logger instance, creating a child logger if `fastify.log` is available, otherwise setting logger to undefined. This enables graceful degradation when a logger is not provided. ```javascript const logger = fastify.log ? fastify.log.child({ plugin: 'fastify-graceful-shutdown' }) : undefined ``` -------------------------------- ### Signal Handling Flow Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/README.md Illustrates the sequence of events when a signal is received, including parallel handler execution, server closure, logger flushing, and process exit. ```text Signal Received ↓ [All handlers run in parallel via Promise.all()] ↓ [Fastify server closes] ↓ [Logger flushes] ↓ [Process exits with code 0 or 1] ``` -------------------------------- ### Basic Usage of fastify-graceful-shutdown Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/START_HERE.md Register the plugin and define a graceful shutdown handler. The handler will be executed when a shutdown signal is received. ```javascript const fastify = require('fastify')() fastify.register(require('fastify-graceful-shutdown')) fastify.after(() => { fastify.gracefulShutdown(async (signal) => { console.log('Shutting down:', signal) // cleanup code }) }) fastify.listen({ port: 3000 }) ``` -------------------------------- ### Register Plugin with Multiple Fastify Instances Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/api-reference-plugin.md When running multiple Fastify instances, set `resetHandlersOnInit: true` for each instance to prevent signal handler conflicts. ```javascript const fastify1 = Fastify() fastify1.register(fastifyGracefulShutdown, { resetHandlersOnInit: true }) const fastify2 = Fastify() fastify2.register(fastifyGracefulShutdown, { resetHandlersOnInit: true }) ``` -------------------------------- ### Fastify Instance Decoration Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/reference.md After registering the plugin, the Fastify instance is decorated with the `gracefulShutdown` method. ```typescript interface FastifyInstance { gracefulShutdown( handler: (signal: string) => Promise | void ): void } ``` -------------------------------- ### Handling Multiple Fastify Instances Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/configuration.md Register fastify-graceful-shutdown with `resetHandlersOnInit: true` for each Fastify instance when running multiple instances in the same process. This prevents conflicts with signal handlers. ```javascript const fastify1 = Fastify() fastify1.register(fastifyGracefulShutdown, { resetHandlersOnInit: true }) const fastify2 = Fastify() fastify2.register(fastifyGracefulShutdown, { resetHandlersOnInit: true }) ``` -------------------------------- ### Default Configuration for Fastify Graceful Shutdown Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/configuration.md Use default settings for graceful shutdown, including a 10-second timeout and standard process signal handling. This is suitable for most applications. ```javascript const Fastify = require('fastify') const fastifyGracefulShutdown = require('fastify-graceful-shutdown') const fastify = Fastify() fastify.register(fastifyGracefulShutdown) fastify.after(() => { fastify.gracefulShutdown(async (signal) => { console.log('Graceful shutdown triggered:', signal) }) }) ``` -------------------------------- ### Plugin Registration and Configuration Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/DOCUMENTATION_SUMMARY.txt This section details how to register the fastify-graceful-shutdown plugin with your Fastify application and configure its behavior. It covers the plugin function signature, available options, and default settings. ```APIDOC ## Plugin Registration and Configuration ### Description This section covers the registration of the `fastify-graceful-shutdown` plugin and its configuration options. It outlines the plugin function signature, parameters, and how to customize shutdown behavior. ### Method `fastify.register()` ### Parameters #### Plugin Options - **`signal`** (string | string[]) - Optional - The signal(s) to listen for to trigger shutdown. Defaults to `SIGTERM`. - **`shutdownTimeout`** (number) - Optional - The maximum time in milliseconds to wait for handlers to complete before forcefully exiting. Defaults to `5000`. - **`logger`** (object | boolean) - Optional - A custom logger instance or a boolean to enable/disable built-in logging. Defaults to `true`. - **`handler`** (function) - Optional - A function to be called when a shutdown signal is received. This function should return a Promise that resolves when cleanup is complete. - **`preShutdown`** (function) - Optional - A function to be called before the shutdown handlers. It can be used for pre-shutdown tasks. - **`forceCloseConnections`** (boolean) - Optional - Whether to forcefully close active connections during shutdown. Defaults to `false`. ### Example ```javascript fastify.register(require('@hemerajs/fastify-graceful-shutdown'), { shutdownTimeout: 10000, logger: true }); ``` ``` -------------------------------- ### Handler Execution Flow Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/reference.md Illustrates the parallel execution of registered handlers during a shutdown sequence, followed by server closure and process exit. Handlers are invoked concurrently using Promise.all. ```text Signal Received ↓ Promise.all([ handler1(signal), handler2(signal), handler3(signal) ]) ↓ [All complete or first fails] ↓ fastify.close() ↓ [Success/Error] ↓ process.exit(0 or 1) ``` -------------------------------- ### Test with Mock Listener Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/reference.md Register the plugin with a mock event listener for testing purposes. The mock listener's exit function is overridden. ```javascript const mockEventListener = new EventEmitter() mockEventListener.exit = (code) => {} fastify.register(fastifyGracefulShutdown, { handlerEventListener: mockEventListener }) ``` -------------------------------- ### Register Plugin and Cleanup Handlers Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/README.md Register the fastify-graceful-shutdown plugin and define cleanup logic within the `gracefulShutdown` handler. This handler will be executed when a shutdown signal is received. Ensure all asynchronous cleanup operations are awaited. ```javascript const fastify = require('fastify')() // Register plugin fastify.register(require('fastify-graceful-shutdown'), { timeout: 10000 // 10 second timeout }) // Register cleanup handlers fastify.after(() => { fastify.gracefulShutdown(async (signal) => { // Cleanup logic await database.close() await cache.disconnect() }) }) ``` -------------------------------- ### Register Fastify Graceful Shutdown Plugin Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/INDEX.md Register the plugin with your Fastify instance. Options can be passed during registration. ```javascript fastify.register(fastifyGracefulShutdown, options) ``` -------------------------------- ### Defensive Handler Implementation with Individual Timeouts Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/usage-examples.md Implement a defensive shutdown handler that iterates through multiple cleanup tasks, each with its own timeout. This prevents a single slow cleanup from blocking the entire shutdown process. Errors during cleanup are logged, and the process continues with other handlers. ```javascript fastify.after(() => { fastify.gracefulShutdown(async (signal) => { const handlers = [ { name: 'database', cleanup: async () => { await db.close() } }, { name: 'cache', cleanup: async () => { await cache.disconnect() } } ] for (const handler of handlers) { try { fastify.log.debug(`Executing ${handler.name} cleanup`) // Individual timeout per cleanup task await Promise.race([ handler.cleanup(), new Promise((_, reject) => setTimeout(() => reject(new Error(`${handler.name} timeout`)), 5000) ) ]) fastify.log.debug(`${handler.name} cleanup successful`) } catch (err) { fastify.log.error({ err, handler: handler.name }, 'Cleanup failed') // Continue with other cleanups rather than throwing } } }) }) ``` -------------------------------- ### Optional Chaining for Logger Calls Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/architecture.md This code illustrates the use of optional chaining (`?.`) for calling logger methods. This prevents errors if the logger or its methods are undefined, ensuring the plugin functions even without a logger. ```javascript logger.debug?.({ signal: signal }, 'Received signal') logger.error?.({ err: err, signal: signal }, 'Process terminated') logger.flush?.() ``` -------------------------------- ### Test with Mock Event Listener Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/README.md Allows for testing shutdown logic without actually emitting system signals. A mock event emitter is provided to control the shutdown process during tests. ```javascript const mockEventListener = new EventEmitter() mockEventListener.exit = () => {} fastify.register(require('fastify-graceful-shutdown'), { handlerEventListener: mockEventListener }) ``` -------------------------------- ### fastifyGracefulShutdownOptions Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/types.md The configuration object passed to the plugin during registration. It allows customization of the shutdown process, including timeout, handler reset behavior, and event listener injection. ```APIDOC ## fastifyGracefulShutdownOptions ### Description The configuration object passed to the plugin during registration. It allows customization of the shutdown process, including timeout, handler reset behavior, and event listener injection. ### Type Definition ```typescript type fastifyGracefulShutdownOptions = { timeout?: number resetHandlersOnInit?: boolean handlerEventListener?: EventEmitter & { exit(code?: number): never } } ``` ### Properties | Property | Type | Required | Default | Description | |----------|------|----------|---------|-------------| | timeout | number | No | `10000` | Maximum time in milliseconds to wait for all registered shutdown handlers to complete before forcefully terminating the process. If handlers don't finish before this timeout, the process will exit with code 1 | | resetHandlersOnInit | boolean | No | `false` | When `true`, removes any signal listeners registered by a previous instance of the plugin before registering new ones. This is useful when creating multiple Fastify instances in the same process to avoid handler conflicts | | handlerEventListener | EventEmitter & { exit(code?: number): never } | No | `process` | A custom event emitter object that implements the signal handler registration API. Must have methods: `once(signal: string, listener: Function)`, `removeListener(signal: string, listener: Function)`, `listenerCount(signal: string)`, and `exit(code?: number)`. Defaults to the Node.js global `process` object. Primarily used for dependency injection in testing scenarios | ### Usage Context This type is used as the second parameter to the plugin registration: ```typescript import Fastify from 'fastify' import fastifyGracefulShutdown from 'fastify-graceful-shutdown' const fastify = Fastify() // With default options fastify.register(fastifyGracefulShutdown) // With custom options fastify.register(fastifyGracefulShutdown, { timeout: 30000, resetHandlersOnInit: true }) // With custom event listener fastify.register(fastifyGracefulShutdown, { handlerEventListener: customEventEmitter }) ``` ``` -------------------------------- ### Error Handling in Shutdown Handler - Fastify Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/api-reference-plugin.md Shows how to implement error handling within a graceful shutdown handler. Any errors thrown during the cleanup process should be caught and logged, and then re-thrown to ensure the shutdown process is aware of the failure. ```javascript fastify.after(() => { fastify.gracefulShutdown(async (signal) => { try { // Perform cleanup fastify.log.info('Starting cleanup') } catch (err) { fastify.log.error({ err }, 'Cleanup failed') throw err } }) }) ``` -------------------------------- ### FastifyInstance Decoration for gracefulShutdown Method Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/types.md Illustrates the type augmentation for the Fastify instance, adding the gracefulShutdown method after the plugin is registered. This method accepts a shutdown handler function. ```typescript declare module 'fastify' { interface FastifyInstance { gracefulShutdown( handler: (signal: string) => Promise | void, ): void } } ``` -------------------------------- ### Register Plugin Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/START_HERE.md This snippet shows how to register the fastify-graceful-shutdown plugin with Fastify. It includes optional configuration parameters for timeout, handler reset, and event listener customization. ```APIDOC ## Register Plugin ### Description Registers the fastify-graceful-shutdown plugin with your Fastify instance. You can configure options like `timeout`, `resetHandlersOnInit`, and `handlerEventListener`. ### Usage ```javascript fastify.register(require('fastify-graceful-shutdown'), { timeout: 10000, // Optional: 10s default resetHandlersOnInit: false, // Optional: remove old handlers handlerEventListener: process // Optional: custom event source }) ``` ### Options * **timeout** (number): The maximum time in milliseconds to wait for handlers to complete before forcing an exit. Defaults to 10000ms (10 seconds). * **resetHandlersOnInit** (boolean): If true, removes any previously registered handlers. Useful when using multiple Fastify instances in the same process. Defaults to false. * **handlerEventListener** (EventEmitter): A custom event emitter to listen for shutdown signals. Defaults to `process`. ``` -------------------------------- ### Registering a Graceful Shutdown Handler Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/reference.md Demonstrates how to register a custom handler function that will be executed when SIGINT or SIGTERM signals are received. The handler can be synchronous or asynchronous. ```typescript gracefulShutdown( handler: (signal: string) => Promise | void ): void ``` -------------------------------- ### Registering Shutdown Handlers with fastify.gracefulShutdown Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/types.md Shows how to register asynchronous and synchronous handler functions with the fastify instance using the gracefulShutdown method. Handlers are executed upon receiving a SIGINT or SIGTERM signal. ```typescript // Async handler fastify.gracefulShutdown(async (signal) => { console.log(`Received ${signal}, closing database`) await database.close() }) // Sync handler fastify.gracefulShutdown((signal) => { console.log(`Received ${signal}, cleaning up`) }) ``` -------------------------------- ### Register Multiple Handlers - Fastify Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/api-reference-plugin.md Illustrates registering multiple independent shutdown handlers by calling `gracefulShutdown()` multiple times. These handlers are stored in an array and executed concurrently when a termination signal is received. ```javascript fastify.after(() => { // Handler 1 fastify.gracefulShutdown(async (signal) => { console.log('Handler 1 executing for signal:', signal) // Cleanup task 1 }) // Handler 2 fastify.gracefulShutdown(async (signal) => { console.log('Handler 2 executing for signal:', signal) // Cleanup task 2 }) }) ``` -------------------------------- ### Parallel Handler Execution Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/architecture.md This code snippet demonstrates parallel execution of all registered handlers using `Promise.all()`. This approach is used for efficiency, assuming handlers are independent and do not rely on sequential execution. ```javascript await Promise.all(handlers.map((handler) => handler(signal))) ``` -------------------------------- ### Customize Shutdown Timeout Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/README.md Configures the maximum time (in milliseconds) the plugin will wait for handlers to complete before forcing a process exit. Default is 5000ms. ```javascript fastify.register(require('fastify-graceful-shutdown'), { timeout: 30000 }) ``` -------------------------------- ### MongoDB Connection Cleanup with Graceful Shutdown Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/usage-examples.md Illustrates how to disconnect from MongoDB gracefully. The shutdown handler ensures the MongoDB client is closed properly. ```javascript const Fastify = require('fastify') const fastifyGracefulShutdown = require('fastify-graceful-shutdown') const { MongoClient } = require('mongodb') const fastify = Fastify() const mongoClient = new MongoClient(process.env.MONGODB_URI) fastify.register(fastifyGracefulShutdown) let db fastify.register(async (fastify) => { await mongoClient.connect() db = mongoClient.db('myapp') fastify.log.info('Connected to MongoDB') }) fastify.after(() => { fastify.gracefulShutdown(async (signal) => { fastify.log.info(`Received ${signal}, disconnecting from MongoDB`) try { await mongoClient.close() fastify.log.info('MongoDB disconnected') } catch (err) { fastify.log.error({ err }, 'Failed to disconnect from MongoDB') } }) }) fastify.get('/users', async (request, reply) => { const collection = db.collection('users') return await collection.find({}).toArray() }) fastify.listen({ port: 3000 }) ``` -------------------------------- ### Register Plugin with Custom Options and Handler Source: https://github.com/hemerajs/fastify-graceful-shutdown/blob/master/_autodocs/README.md Register the fastify-graceful-shutdown plugin with custom options and define a graceful shutdown handler in TypeScript. ```typescript import fastifyGracefulShutdown from 'fastify-graceful-shutdown' fastify.register(fastifyGracefulShutdown, { timeout: 30000, resetHandlersOnInit: false }) fastify.gracefulShutdown(async (signal: string) => { // signal is "SIGINT" or "SIGTERM" }) ```