Skip to content

Commit a852827

Browse files
committed
systemd: $MAINPID handover for NotifyAccess=main
1 parent de7f118 commit a852827

File tree

3 files changed

+26
-5
lines changed

3 files changed

+26
-5
lines changed

docs/source/settings.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1595,6 +1595,11 @@ If the ``PORT`` environment variable is defined, the default
15951595
is ``['0.0.0.0:$PORT']``. If it is not defined, the default
15961596
is ``['127.0.0.1:8000']``.
15971597

1598+
.. note::
1599+
Specifying any fd://FD socket or inheriting any socket from systemd
1600+
(LISTEN_FDS) results in other bind addresses to be skipped.
1601+
Do not mix fd://FD and systemd socket activation.
1602+
15981603
.. _backlog:
15991604

16001605
``backlog``

gunicorn/arbiter.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -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 = []
@@ -350,7 +351,12 @@ def wakeup(self):
350351

351352
def halt(self, reason=None, exit_status=0):
352353
""" halt arbiter """
353-
systemd.sd_notify("STOPPING=1\nSTATUS=Gunicorn shutting down..", self.log)
354+
if self.master_pid != 0:
355+
# if NotifyAccess=main, systemd needs to know old master is in control
356+
systemd.sd_notify("READY=1\nMAINPID=%d\nSTATUS=New arbiter shutdown" % (self.master_pid, ), self.log)
357+
elif self.reexec_pid == 0:
358+
# skip setting status if this is merely superseded master stopping
359+
systemd.sd_notify("STOPPING=1\nSTATUS=Shutting down..", self.log)
354360

355361
self.stop()
356362

@@ -425,6 +431,10 @@ def reexec(self):
425431
master_pid = os.getpid()
426432
self.reexec_pid = os.fork()
427433
if self.reexec_pid != 0:
434+
# let systemd know they will be in control after exec()
435+
systemd.sd_notify(
436+
"RELOADING=1\nMAINPID=%d\nSTATUS=Gunicorn arbiter re-exec in forked.." % (self.reexec_pid, ), self.log
437+
)
428438
# old master
429439
return
430440

@@ -445,8 +455,10 @@ def reexec(self):
445455

446456
# exec the process using the original environment
447457
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\nMAINPID=%d\nSTATUS=Gunicorn arbiter re-exec" % (master_pid, ), self.log)
458+
# let systemd know we will be in control after exec()
459+
systemd.sd_notify(
460+
"RELOADING=1\nMAINPID=%d\nSTATUS=Gunicorn arbiter re-exec in progress.." % (os.getpid(), ), self.log
461+
)
450462
os.execve(self.START_CTX[0], self.START_CTX['args'], environ)
451463

452464
def reload(self):
@@ -538,8 +550,7 @@ def reap_workers(self):
538550
self.reexec_pid = 0
539551
self.log.info("Master exited before promotion.")
540552
# let systemd know we are (back) in control
541-
systemd.sd_notify("READY=1\nMAINPID=%d\nSTATUS=Gunicorn arbiter re-exec aborted" % (os.getpid(), ), self.log)
542-
continue
553+
systemd.sd_notify("READY=1\nMAINPID=%d\nSTATUS=Old arbiter promoted" % (os.getpid(), ), self.log)
543554
else:
544555
worker = self.WORKERS.pop(wpid, None)
545556
if not worker:

gunicorn/config.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,11 @@ class Bind(Setting):
616616
If the ``PORT`` environment variable is defined, the default
617617
is ``['0.0.0.0:$PORT']``. If it is not defined, the default
618618
is ``['127.0.0.1:8000']``.
619+
620+
.. note::
621+
Specifying any fd://FD socket or inheriting any socket from systemd
622+
(LISTEN_FDS) results in other bind addresses to be skipped.
623+
Do not mix fd://FD and systemd socket activation.
619624
"""
620625

621626

0 commit comments

Comments
 (0)