# HG changeset patch # User Kim Alvefur # Date 1462455781 -7200 # Node ID 4652a112a4ba16f3b09746e4cef3aed9c8422598 # Parent 9fa588babbba2a389dcd2a246728bae84213ef2f mod_graceful_shutdown: Experiment in improving the shutdown experience diff -r 9fa588babbba -r 4652a112a4ba mod_graceful_shutdown/README.markdown --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mod_graceful_shutdown/README.markdown Thu May 05 15:43:01 2016 +0200 @@ -0,0 +1,26 @@ +This module is an experiment about a more graceful shutdown process. + +Why +=== + +When shutting down, a number of sessions, connections and other things +are teared down. Due to all these things happening very quickly, +sometimes eg client unavailable notifications don't make it to all +remote contacts because the server-to-server connections are teared down +just after. + +How +=== + +This module works by breaking the shutdown process into separate steps +with a brief pause between them. + +It goes something like this + +1. Stop accepting new client connections. +2. Close all client connections. +3. Fire event for everything else. +4. Tell `net.server` to quit the main loop. +5. ??? +6. Still here? Kill itself. + diff -r 9fa588babbba -r 4652a112a4ba mod_graceful_shutdown/mod_graceful_shutdown.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mod_graceful_shutdown/mod_graceful_shutdown.lua Thu May 05 15:43:01 2016 +0200 @@ -0,0 +1,42 @@ +-- luacheck: ignore 122/prosody 113/prosody + +local timer = require "util.timer"; +local portman = require "core.portmanager"; +local server = require "net.server"; + +module:set_global(); +local orig_shutdown = prosody.shutdown; + +local pause = module:get_option_number("shutdown_pause", 1); + +function module.unload() + prosody.shutdown = orig_shutdown; +end + +prosody.shutdown = coroutine.wrap(function (reason, code) + prosody.shutdown_reason = reason; + prosody.shutdown_code = code; + timer.add_task(pause, prosody.shutdown); + coroutine.yield(true, "shutdown initiated"); + -- Close c2s ports, stop accepting new connections + portman.deactivate("c2s"); + -- Close all c2s sessions + for _, sess in pairs(prosody.full_sessions) do + sess:close{ condition = "system-shutdown", text = reason } + end + -- Wait for notifications to be sent + coroutine.yield(pause); + -- Event for everything else to shut down + prosody.events.fire_event("server-stopping", { + reason = reason; + code = code; + }); + -- And wait + coroutine.yield(pause); + -- And stop main event loop + server.setquitting(true); + -- And wait for death + coroutine.yield(pause * 3); + -- you came back? die zombie! + os.exit(1); +end);