@@ -2,48 +2,121 @@ import cluster from 'cluster';
22import { FastifyInstance } from './types.js' ;
33import { SHUTDOWN_WORKER_MESSAGE } from '../shared/utils.js' ;
44import log from '../shared/log.js' ;
5+ import { onMessageEnded , onMessageInitiated } from '../workerMessagesRouter.js' ;
6+
7+ type GracefulShutdownController = {
8+ readonly activeRequestsCount : number ;
9+ readonly activeMessageChannelsCount : number ;
10+ readonly isShuttingDown : boolean ;
11+ markNewRequestReceived : ( ) => void ;
12+ markRequestHandled : ( ) => void ;
13+ markNewMessageChannelOpened : ( ) => void ;
14+ markMessageChannelClosed : ( ) => void ;
15+ } ;
16+
17+ let gracefulShutdownController : GracefulShutdownController ;
18+
19+ const setupGracefulShutdownHandler = ( ) => {
20+ if ( gracefulShutdownController ) {
21+ return gracefulShutdownController ;
22+ }
523
6- const handleGracefulShutdown = ( app : FastifyInstance ) => {
724 const { worker } = cluster ;
825 if ( ! worker ) {
9- log . error ( 'handleGracefulShutdown is called on master, expected to call it on worker only' ) ;
10- return ;
26+ log . error ( 'setupGracefulShutdownHandler is called on master, expected to call it on worker only' ) ;
27+ return undefined ;
1128 }
1229
1330 let activeRequestsCount = 0 ;
31+ let activeMessageChannelsCount = 0 ;
1432 let isShuttingDown = false ;
1533
34+ const handleCloseEvent = ( ) => {
35+ if ( ! isShuttingDown ) {
36+ return ;
37+ }
38+
39+ if ( activeMessageChannelsCount > 0 ) {
40+ log . info (
41+ 'Worker #%d has "%d" active message channels, keep the worker connected' ,
42+ worker . id ,
43+ activeMessageChannelsCount ,
44+ ) ;
45+ } else if ( activeRequestsCount > 0 ) {
46+ log . info (
47+ 'Worker #%d has "%d" active requests, disconnecting the worker' ,
48+ worker . id ,
49+ activeRequestsCount ,
50+ ) ;
51+ worker . disconnect ( ) ;
52+ } else {
53+ log . info ( 'Worker #%d has no active requests, killing the worker' , worker . id ) ;
54+ worker . destroy ( ) ;
55+ }
56+ } ;
57+
58+ gracefulShutdownController = {
59+ get activeRequestsCount ( ) {
60+ return activeRequestsCount ;
61+ } ,
62+ get activeMessageChannelsCount ( ) {
63+ return activeMessageChannelsCount ;
64+ } ,
65+ get isShuttingDown ( ) {
66+ return isShuttingDown ;
67+ } ,
68+ markNewRequestReceived : ( ) => {
69+ activeRequestsCount += 1 ;
70+ } ,
71+ markRequestHandled : ( ) => {
72+ activeRequestsCount -= 1 ;
73+ handleCloseEvent ( ) ;
74+ } ,
75+ markNewMessageChannelOpened : ( ) => {
76+ activeMessageChannelsCount += 1 ;
77+ } ,
78+ markMessageChannelClosed : ( ) => {
79+ activeMessageChannelsCount -= 1 ;
80+ handleCloseEvent ( ) ;
81+ } ,
82+ } ;
83+
1684 process . on ( 'message' , ( msg ) => {
1785 if ( msg === SHUTDOWN_WORKER_MESSAGE ) {
18- log . debug ( 'Worker #%d received graceful shutdown message' , worker . id ) ;
86+ log . info ( 'Worker #%d received graceful shutdown message' , worker . id ) ;
1987 isShuttingDown = true ;
20- if ( activeRequestsCount === 0 ) {
21- log . debug ( 'Worker #%d has no active requests, killing the worker' , worker . id ) ;
22- worker . destroy ( ) ;
23- } else {
24- log . debug (
25- 'Worker #%d has "%d" active requests, disconnecting the worker' ,
26- worker . id ,
27- activeRequestsCount ,
28- ) ;
29- worker . disconnect ( ) ;
30- }
88+ handleCloseEvent ( ) ;
3189 }
3290 } ) ;
3391
92+ return gracefulShutdownController ;
93+ } ;
94+
95+ const handleGracefulShutdown = ( app : FastifyInstance ) => {
96+ const controller = setupGracefulShutdownHandler ( ) ;
97+ if ( ! controller ) {
98+ return ;
99+ }
100+
34101 app . addHook ( 'onRequest' , ( _req , _reply , done ) => {
35- activeRequestsCount += 1 ;
102+ controller . markNewRequestReceived ( ) ;
36103 done ( ) ;
37104 } ) ;
38105
39106 app . addHook ( 'onResponse' , ( _req , _reply , done ) => {
40- activeRequestsCount -= 1 ;
41- if ( isShuttingDown && activeRequestsCount === 0 ) {
42- log . debug ( 'Worker #%d served all active requests and going to be killed' , worker . id ) ;
43- worker . destroy ( ) ;
44- }
107+ controller . markRequestHandled ( ) ;
45108 done ( ) ;
46109 } ) ;
47110} ;
48111
112+ onMessageInitiated ( ( ) => {
113+ const controller = setupGracefulShutdownHandler ( ) ;
114+ controller ?. markNewMessageChannelOpened ( ) ;
115+ } ) ;
116+
117+ onMessageEnded ( ( ) => {
118+ const controller = setupGracefulShutdownHandler ( ) ;
119+ controller ?. markMessageChannelClosed ( ) ;
120+ } ) ;
121+
49122export default handleGracefulShutdown ;
0 commit comments