Skip to content

Commit 9184ae8

Browse files
gdamjanbenoitc
authored andcommitted
add systemd sd_notify support (#1897)
* add systemd sd_notify support roughly based on sd_notify() from systemd and https://github.com/bb4242/sdnotify only implements `READY=1` and `STATUS=Gunicorn arbiter booted` of the protocol in the arbiter. in the future, reloads can be notified, and possibly also other statuses. see https://www.freedesktop.org/software/systemd/man/sd_notify.html for more info sd_notify() is a noop when not run in a systemd service (i.e NOTIFY_SOCKET environment variable is not set)
1 parent ad1afe7 commit 9184ae8

File tree

3 files changed

+34
-1
lines changed

3 files changed

+34
-1
lines changed

docs/source/deploy.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ unix socket:
227227
After=network.target
228228

229229
[Service]
230-
PIDFile=/run/gunicorn/pid
230+
Type=notify
231231
User=someuser
232232
Group=someuser
233233
RuntimeDirectory=gunicorn

gunicorn/arbiter.py

+1
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ def start(self):
158158
self.log.debug("Arbiter booted")
159159
self.log.info("Listening at: %s (%s)", listeners_str, self.pid)
160160
self.log.info("Using worker: %s", self.cfg.worker_class_str)
161+
systemd.sd_notify("READY=1\nSTATUS=Gunicorn arbiter booted", self.log)
161162

162163
# check worker class requirements
163164
if hasattr(self.worker_class, "check_config"):

gunicorn/systemd.py

+32
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
# See the NOTICE for more information.
55

66
import os
7+
import socket
78

89
SD_LISTEN_FDS_START = 3
910

@@ -43,3 +44,34 @@ def listen_fds(unset_environment=True):
4344
os.environ.pop('LISTEN_FDS', None)
4445

4546
return fds
47+
48+
49+
def sd_notify(state, logger, unset_environment=False):
50+
"""Send a notification to systemd. state is a string; see
51+
the man page of sd_notify (http://www.freedesktop.org/software/systemd/man/sd_notify.html)
52+
for a description of the allowable values.
53+
54+
If the unset_environment parameter is True, sd_notify() will unset
55+
the $NOTIFY_SOCKET environment variable before returning (regardless of
56+
whether the function call itself succeeded or not). Further calls to
57+
sd_notify() will then fail, but the variable is no longer inherited by
58+
child processes.
59+
"""
60+
61+
62+
addr = os.environ.get('NOTIFY_SOCKET')
63+
if addr is None:
64+
# not run in a service, just a noop
65+
return
66+
try:
67+
sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM | socket.SOCK_CLOEXEC)
68+
if addr[0] == '@':
69+
addr = '\0' + addr[1:]
70+
sock.connect(addr)
71+
sock.sendall(state.encode('utf-8'))
72+
except:
73+
logger.debug("Exception while invoking sd_notify()", exc_info=True)
74+
finally:
75+
if unset_environment:
76+
os.environ.pop('NOTIFY_SOCKET')
77+
sock.close()

0 commit comments

Comments
 (0)