@@ -150,6 +150,7 @@ def start(self):
150150 self .systemd = True
151151 fds = range (systemd .SD_LISTEN_FDS_START ,
152152 systemd .SD_LISTEN_FDS_START + listen_fds )
153+ self .log .debug ("Inherited sockets from systemd: %r" , fds )
153154
154155 elif self .master_pid :
155156 fds = []
@@ -170,6 +171,10 @@ def start(self):
170171
171172 self .cfg .when_ready (self )
172173
174+ # # call `pkill --oldest -TERM -f "gunicorn: master "` instead
175+ # if self.master_pid and self.systemd:
176+ # os.kill(self.master_pid, signal.SIGTERM)
177+
173178 def init_signals (self ):
174179 """\
175180 Initialize master signal handling. Most of the signals
@@ -348,7 +353,12 @@ def wakeup(self):
348353
349354 def halt (self , reason = None , exit_status = 0 ):
350355 """ halt arbiter """
351- systemd .sd_notify ("STOPPING=1\n STATUS=Gunicorn shutting down..\n " , self .log )
356+ if self .master_pid != 0 :
357+ # if NotifyAccess=main, systemd needs to know old master is in control
358+ systemd .sd_notify ("READY=1\n MAINPID=%d\n STATUS=New arbiter shutdown\n " % (self .master_pid , ), self .log )
359+ elif self .reexec_pid == 0 :
360+ # skip setting status if this is merely superseded master stopping
361+ systemd .sd_notify ("STOPPING=1\n STATUS=Shutting down..\n " , self .log )
352362
353363 self .stop ()
354364
@@ -423,6 +433,10 @@ def reexec(self):
423433 master_pid = os .getpid ()
424434 self .reexec_pid = os .fork ()
425435 if self .reexec_pid != 0 :
436+ # let systemd know they will be in control after exec()
437+ systemd .sd_notify (
438+ "RELOADING=1\n MAINPID=%d\n STATUS=Gunicorn arbiter re-exec in forked..\n " % (self .reexec_pid , ), self .log
439+ )
426440 # old master
427441 return
428442
@@ -435,6 +449,9 @@ def reexec(self):
435449 if self .systemd :
436450 environ ['LISTEN_PID' ] = str (os .getpid ())
437451 environ ['LISTEN_FDS' ] = str (len (self .LISTENERS ))
452+ # move socket fds back to 3+N after we duped+closed them
453+ # for idx, lnr in enumerate(self.LISTENERS):
454+ # os.dup2(lnr.fileno(), 3+idx)
438455 else :
439456 environ ['GUNICORN_FD' ] = ',' .join (
440457 str (lnr .fileno ()) for lnr in self .LISTENERS )
@@ -443,8 +460,10 @@ def reexec(self):
443460
444461 # exec the process using the original environment
445462 self .log .debug ("exe=%r argv=%r" % (self .START_CTX [0 ], self .START_CTX ['args' ]))
446- # let systemd know are are in control
447- systemd .sd_notify ("READY=1\n MAINPID=%d\n STATUS=Gunicorn arbiter re-exec\n " % (master_pid , ), self .log )
463+ # let systemd know we will be in control after exec()
464+ systemd .sd_notify (
465+ "RELOADING=1\n MAINPID=%d\n STATUS=Gunicorn arbiter re-exec in progress..\n " % (self .reexec_pid , ), self .log
466+ )
448467 os .execve (self .START_CTX [0 ], self .START_CTX ['args' ], environ )
449468
450469 def reload (self ):
@@ -536,8 +555,7 @@ def reap_workers(self):
536555 self .reexec_pid = 0
537556 self .log .info ("Master exited before promotion." )
538557 # let systemd know we are (back) in control
539- systemd .sd_notify ("READY=1\n MAINPID=%d\n STATUS=Gunicorn arbiter re-exec aborted\n " % (os .getpid (), ), self .log )
540- continue
558+ systemd .sd_notify ("READY=1\n MAINPID=%d\n STATUS=Old arbiter promoted\n " % (os .getpid (), ), self .log )
541559 else :
542560 worker = self .WORKERS .pop (wpid , None )
543561 if not worker :
0 commit comments