diff --git a/webservice/common.py b/webservice/common.py new file mode 100644 index 0000000000000000000000000000000000000000..84f47617f16fadb68bd2326817955a6e11768cc1 --- /dev/null +++ b/webservice/common.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: MIT-0 +# +# Implement the systemd notify protocol without external dependencies. +# Taken from the sd_notify man page + +import errno +import os +import socket + +def notify(message): + if not message: + raise ValueError("notify() requires a message") + + if not (socket_path := os.environ.get("NOTIFY_SOCKET")): + return # Not started by systemd + + if socket_path[0] not in ("/", "@"): + raise OSError(errno.EAFNOSUPPORT, "Unsupported socket type") + + # Handle abstract socket. + if socket_path[0] == "@": + socket_path = "\0" + socket_path[1:] + + with socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM | socket.SOCK_CLOEXEC) as sock: + sock.connect(socket_path) + sock.sendall(message) + +def notify_ready(): + notify(b"READY=1") diff --git a/webservice/job_monitor.py b/webservice/job_monitor.py index 9023620d6ee0da66d16db94ad2c8b28d55d03a59..b9a6b5fcbce62a4e4b3b862368b51a486bc1b528 100644 --- a/webservice/job_monitor.py +++ b/webservice/job_monitor.py @@ -15,10 +15,12 @@ from kafka import KafkaProducer from kafka.errors import KafkaError try: + from .common import notify_ready from .config import webservice as config from .messages import MDC, Errors, MigrationError, Success from .webservice import init_job_db, init_md_client, time_db_transaction except ImportError: + from common import notify_ready from config import webservice as config from messages import MDC, Errors, MigrationError, Success from webservice import init_job_db, init_md_client, time_db_transaction @@ -419,6 +421,7 @@ def main(argv=None): signal.signal(signal.SIGTERM, interrupted) with JobsMonitor(config) as jm: + notify_ready() try: jm.run() except KeyboardInterrupt: diff --git a/webservice/serve_overview.py b/webservice/serve_overview.py index dabfae7e46e6a84faca59061c4d3e940181c854b..3ce5f3da8664624012a5a9d8423118bce70c9767 100644 --- a/webservice/serve_overview.py +++ b/webservice/serve_overview.py @@ -17,8 +17,10 @@ from jinja2 import Template from xfel_calibrate.settings import free_nodes_cmd, preempt_nodes_cmd try: + from .common import notify_ready from .config import serve_overview as config except: + from common import notify_ready from config import serve_overview as config @@ -344,6 +346,7 @@ def run(config_file: Optional[str] = None): server_address = (sconfig["host"], sconfig["port"]) httpd = HTTPServer(server_address, RequestHandler) print('running server...', flush=True) + notify_ready() httpd.serve_forever() diff --git a/webservice/systemd/cal-job-monitor.service b/webservice/systemd/cal-job-monitor.service index 72fad67d63acb539643d2a55b0f1ecf113fcd999..7c330eb19b8a5d666b74b4cd80a5ec84270fa403 100644 --- a/webservice/systemd/cal-job-monitor.service +++ b/webservice/systemd/cal-job-monitor.service @@ -3,11 +3,9 @@ Description=XFEL offline calibration Slurm job monitor PartOf=cal-services.target [Service] -Type=exec +Type=notify WorkingDirectory=%h/deployments/development/git.xfel.eu/detectors/pycalibration/current/ ExecStart=%h/deployments/development/git.xfel.eu/detectors/pycalibration/current/.venv/bin/python -m webservice.job_monitor --log-level DEBUG -# Pause to make errors in startup more obvious -ExecStartPost=/usr/bin/sleep 1 Restart=on-failure SyslogIdentifier=job_monitor diff --git a/webservice/systemd/cal-overview-server.service b/webservice/systemd/cal-overview-server.service index 6c186ef6c45c6c0a12acdc1d673a0fedfa337d0e..685cf71e09a979a0867a9be9ee14bfa71bb4a417 100644 --- a/webservice/systemd/cal-overview-server.service +++ b/webservice/systemd/cal-overview-server.service @@ -3,11 +3,9 @@ Description=XFEL offline calibration status web page PartOf=cal-services.target [Service] -Type=exec +Type=notify WorkingDirectory=%h/deployments/development/git.xfel.eu/detectors/pycalibration/current/ ExecStart=%h/deployments/development/git.xfel.eu/detectors/pycalibration/current/.venv/bin/python -m webservice.serve_overview -# Pause to make errors in startup more obvious -ExecStartPost=/usr/bin/sleep 1 Restart=on-failure SyslogIdentifier=serve_overview diff --git a/webservice/systemd/cal-webservice.service b/webservice/systemd/cal-webservice.service index 1456ca56a88fb27c8a9e86d68d06f3353adb9ede..64e8fed31ce7cd64986dcedfa04c1079cb580057 100644 --- a/webservice/systemd/cal-webservice.service +++ b/webservice/systemd/cal-webservice.service @@ -3,11 +3,9 @@ Description=XFEL offline calibration ZMQ service PartOf=cal-services.target [Service] -Type=exec +Type=notify WorkingDirectory=%h/deployments/development/git.xfel.eu/detectors/pycalibration/current/ ExecStart=%h/deployments/development/git.xfel.eu/detectors/pycalibration/current/.venv/bin/python -m webservice.webservice --mode prod --log-level DEBUG -# Pause to make errors in startup more obvious -ExecStartPost=/usr/bin/sleep 1 Restart=on-failure SyslogIdentifier=webservice diff --git a/webservice/webservice.py b/webservice/webservice.py index 3c9b5056839354a6d935bc2df03a1fc8a76e52c7..54e94ddd0810af7bbeb8e862f910f2f044b87706 100644 --- a/webservice/webservice.py +++ b/webservice/webservice.py @@ -33,6 +33,7 @@ from git import InvalidGitRepositoryError, Repo from metadata_client.metadata_client import MetadataClient try: + from .common import notify_ready from .config import webservice as config from .messages import ( MDC, @@ -43,6 +44,7 @@ try: Success, ) except ImportError: + from common import notify_ready from config import webservice as config from messages import MDC, Errors, MigrationError, Success, PDUsNotFoundError, OperationModeNotFoundError @@ -1644,6 +1646,7 @@ def main(argv: Optional[List[str]] = None): # Launch the ZMQ server to handle requests for calibration server = ActionsServer(config, mode) + notify_ready() loop = asyncio.get_event_loop() loop.run_until_complete(server.run()) loop.close()