@@ -151,6 +151,7 @@ def start(self):
151151 self .systemd = True
152152 fds = range (systemd .SD_LISTEN_FDS_START ,
153153 systemd .SD_LISTEN_FDS_START + listen_fds )
154+ self .log .debug ("Inherited sockets from systemd: %r" , fds )
154155
155156 elif self .master_pid :
156157 fds = []
@@ -172,6 +173,10 @@ def start(self):
172173
173174 self .cfg .when_ready (self )
174175
176+ # # call `pkill --oldest -TERM -f "gunicorn: master "` instead
177+ # if self.master_pid and self.systemd:
178+ # os.kill(self.master_pid, signal.SIGTERM)
179+
175180 def init_signals (self ):
176181 """\
177182 Initialize master signal handling. Most of the signals
@@ -350,7 +355,12 @@ def wakeup(self):
350355
351356 def halt (self , reason = None , exit_status = 0 ):
352357 """ halt arbiter """
353- systemd .sd_notify ("STOPPING=1\n STATUS=Gunicorn shutting down..\n " , self .log )
358+ if self .master_pid != 0 :
359+ # if NotifyAccess=main, systemd needs to know old master is in control
360+ systemd .sd_notify ("READY=1\n MAINPID=%d\n STATUS=New arbiter shutdown\n " % (self .master_pid , ), self .log )
361+ elif self .reexec_pid == 0 :
362+ # skip setting status if this is merely superseded master stopping
363+ systemd .sd_notify ("STOPPING=1\n STATUS=Shutting down..\n " , self .log )
354364
355365 self .stop ()
356366
@@ -425,6 +435,10 @@ def reexec(self):
425435 master_pid = os .getpid ()
426436 self .reexec_pid = os .fork ()
427437 if self .reexec_pid != 0 :
438+ # let systemd know they will be in control after exec()
439+ systemd .sd_notify (
440+ "RELOADING=1\n MAINPID=%d\n STATUS=Gunicorn arbiter re-exec in forked..\n " % (self .reexec_pid , ), self .log
441+ )
428442 # old master
429443 return
430444
@@ -437,6 +451,9 @@ def reexec(self):
437451 if self .systemd :
438452 environ ['LISTEN_PID' ] = str (os .getpid ())
439453 environ ['LISTEN_FDS' ] = str (len (self .LISTENERS ))
454+ # move socket fds back to 3+N after we duped+closed them
455+ # for idx, lnr in enumerate(self.LISTENERS):
456+ # os.dup2(lnr.fileno(), 3+idx)
440457 else :
441458 environ ['GUNICORN_FD' ] = ',' .join (
442459 str (lnr .fileno ()) for lnr in self .LISTENERS )
@@ -445,8 +462,10 @@ def reexec(self):
445462
446463 # exec the process using the original environment
447464 self .log .debug ("exe=%r argv=%r" % (self .START_CTX [0 ], self .START_CTX ['args' ]))
448- # let systemd know are are in control
449- systemd .sd_notify ("READY=1\n MAINPID=%d\n STATUS=Gunicorn arbiter re-exec\n " % (master_pid , ), self .log )
465+ # let systemd know we will be in control after exec()
466+ systemd .sd_notify (
467+ "RELOADING=1\n MAINPID=%d\n STATUS=Gunicorn arbiter re-exec in progress..\n " % (self .reexec_pid , ), self .log
468+ )
450469 os .execve (self .START_CTX [0 ], self .START_CTX ['args' ], environ )
451470
452471 def reload (self ):
@@ -538,8 +557,7 @@ def reap_workers(self):
538557 self .reexec_pid = 0
539558 self .log .info ("Master exited before promotion." )
540559 # let systemd know we are (back) in control
541- systemd .sd_notify ("READY=1\n MAINPID=%d\n STATUS=Gunicorn arbiter re-exec aborted\n " % (os .getpid (), ), self .log )
542- continue
560+ systemd .sd_notify ("READY=1\n MAINPID=%d\n STATUS=Old arbiter promoted\n " % (os .getpid (), ), self .log )
543561 else :
544562 worker = self .WORKERS .pop (wpid , None )
545563 if not worker :
0 commit comments