util.startup: Support systemd Type=notify service type
authorKim Alvefur <zash@zash.se>
Thu, 04 Apr 2024 19:00:27 +0200
changeset 13475 afad3b2725bf
parent 13473 f9171624fd03
child 13476 d5a9847b0e55
util.startup: Support systemd Type=notify service type This lets Prosody report its lifecycle status to systemd, so it knows when Prosody has completed its startup, when it's reloading and shutting down. Both Type=notify and Type=notify-reload is supported Example systemd .service configuration snippet: [Service] Type=notify
CHANGES
util/startup.lua
--- a/CHANGES	Thu Mar 28 15:39:59 2024 +0100
+++ b/CHANGES	Thu Apr 04 19:00:27 2024 +0200
@@ -66,6 +66,7 @@
 - Intervals of mod_cron managed periodic jobs made configurable
 - When mod_smacks is enabled, s2s connections not responding to ack requests are closed.
 - Arguments to `prosodyctl shell` that start with ':' are now turned into method calls
+- Support for Type=notify and notify-reload systemd service type added
 
 ## Removed
 
--- a/util/startup.lua	Thu Mar 28 15:39:59 2024 +0100
+++ b/util/startup.lua	Thu Apr 04 19:00:27 2024 +0200
@@ -809,6 +809,39 @@
 	end);
 end
 
+function startup.systemd_notify()
+	local notify_socket_name = os.getenv("NOTIFY_SOCKET");
+	if not notify_socket_name then return end
+	local have_unix, unix = pcall(require, "socket.unix");
+	if not have_unix or type(unix) ~= "table" then
+		log("error", "LuaSocket without UNIX socket support, can't notify systemd.")
+		return os.exit(1);
+	end
+	log("debug", "Will notify on socket %q", notify_socket_name);
+	notify_socket_name = notify_socket_name:gsub("^@", "\0");
+	local notify_socket = unix.dgram();
+	local ok, err = notify_socket:setpeername(notify_socket_name);
+	if not ok then
+		log("error", "Could not connect to systemd notification socket %q: %q", notify_socket_name, err);
+		return os.exit(1);
+	end
+	local time = require "prosody.util.time";
+
+	prosody.notify_socket = notify_socket;
+	prosody.events.add_handler("server-started", function()
+		notify_socket:send("READY=1");
+	end);
+	prosody.events.add_handler("config-reloading", function()
+		notify_socket:send(string.format("RELOADING=1\nMONOTONIC_USEC=%d", math.floor(time.monotonic() * 1000000)));
+	end);
+	prosody.events.add_handler("config-reloaded", function()
+		notify_socket:send("READY=1");
+	end);
+	prosody.events.add_handler("server-stopping", function()
+		notify_socket:send("STOPPING=1");
+	end);
+end
+
 function startup.cleanup()
 	prosody.log("info", "Shutdown status: Cleaning up");
 	prosody.events.fire_event("server-cleanup");
@@ -890,6 +923,7 @@
 	startup.posix_daemonize();
 	startup.write_pidfile();
 	startup.hook_posix_signals();
+	startup.systemd_notify();
 	startup.prepare_to_start();
 	startup.notify_started();
 end