Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit e5f9915

Browse files
committedAug 23, 2024·
systemd: send MAINPID updates on re-exec
1 parent 63a54b0 commit e5f9915

File tree

2 files changed

+25
-4
lines changed

2 files changed

+25
-4
lines changed
 

‎gunicorn/arbiter.py

+17-4
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,11 @@ def __init__(self, app):
6767

6868
cwd = util.getcwd()
6969

70-
args = sys.argv[:]
71-
args.insert(0, sys.executable)
70+
if sys.version_info < (3, 10):
71+
args = sys.argv[:]
72+
args.insert(0, sys.executable)
73+
else:
74+
args = sys.orig_argv[:]
7275

7376
# init start context
7477
self.START_CTX = {
@@ -159,7 +162,7 @@ def start(self):
159162
self.log.debug("Arbiter booted")
160163
self.log.info("Listening at: %s (%s)", listeners_str, self.pid)
161164
self.log.info("Using worker: %s", self.cfg.worker_class_str)
162-
systemd.sd_notify("READY=1\nSTATUS=Gunicorn arbiter booted", self.log)
165+
systemd.sd_notify("READY=1\nSTATUS=Gunicorn arbiter booted\n", self.log)
163166

164167
# check worker class requirements
165168
if hasattr(self.worker_class, "check_config"):
@@ -251,7 +254,10 @@ def handle_hup(self):
251254
- Gracefully shutdown the old worker processes
252255
"""
253256
self.log.info("Hang up: %s", self.master_name)
257+
systemd.sd_notify("RELOADING=1\nSTATUS=Gunicorn arbiter reloading..\n", self.log)
254258
self.reload()
259+
# possibly premature, newly launched workers might have failed
260+
systemd.sd_notify("READY=1\nSTATUS=Gunicorn arbiter reloaded\n", self.log)
255261

256262
def handle_term(self):
257263
"SIGTERM handling"
@@ -327,6 +333,8 @@ def maybe_promote_master(self):
327333
self.pidfile.rename(self.cfg.pidfile)
328334
# reset proctitle
329335
util._setproctitle("master [%s]" % self.proc_name)
336+
# MAINPID does not change here, it was already set on fork
337+
systemd.sd_notify("READY=1\nMAINPID=%d\nSTATUS=Gunicorn arbiter promoted\n" % (os.getpid(), ), self.log)
330338

331339
def wakeup(self):
332340
"""\
@@ -432,7 +440,10 @@ def reexec(self):
432440
os.chdir(self.START_CTX['cwd'])
433441

434442
# exec the process using the original environment
435-
os.execvpe(self.START_CTX[0], self.START_CTX['args'], environ)
443+
self.log.info("%r %r" % (self.START_CTX[0], self.START_CTX['args']))
444+
# let systemd know are are in control
445+
systemd.sd_notify("READY=1\nMAINPID=%d\nSTATUS=Gunicorn arbiter re-exec\n" % (os.getpid(), ), self.log)
446+
os.execve(self.START_CTX[0], self.START_CTX['args'], environ)
436447

437448
def reload(self):
438449
old_address = self.cfg.address
@@ -522,6 +533,8 @@ def reap_workers(self):
522533
if self.reexec_pid == wpid:
523534
self.reexec_pid = 0
524535
self.log.info("Master exited before promotion.")
536+
# let systemd know we are (back) in control
537+
systemd.sd_notify("READY=1\nMAINPID=%d\nSTATUS=Gunicorn arbiter re-exec aborted\n" % (os.getpid(), ), self.log)
525538
continue
526539
else:
527540
worker = self.WORKERS.pop(wpid, None)

‎gunicorn/systemd.py

+8
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import os
66
import socket
7+
import time
78

89
SD_LISTEN_FDS_START = 3
910

@@ -66,6 +67,13 @@ def sd_notify(state, logger, unset_environment=False):
6667
if addr[0] == '@':
6768
addr = '\0' + addr[1:]
6869
sock.connect(addr)
70+
assert state.endswith("\n")
71+
if "RELOADING" in state: # broad, but systemd man promises tolerating
72+
# wrong clock on some platforms.. but this is only needed on Linux
73+
# nsec = 10**-9
74+
# usec = 10**-6
75+
state += "MONOTONIC_USEC=%d\n" % (1_000*time.monotonic_ns(), )
76+
logger.debug("sd_notify: %r" % (state, ))
6977
sock.sendall(state.encode('utf-8'))
7078
except Exception:
7179
logger.debug("Exception while invoking sd_notify()", exc_info=True)

0 commit comments

Comments
 (0)
Please sign in to comment.