From 4aaef5fdf4dd2c6093f388d5d575e90d23c974be Mon Sep 17 00:00:00 2001 From: Erik Arvstedt Date: Mon, 20 Jan 2025 22:47:40 +0100 Subject: [PATCH] services: use `wants` dependency where possible Let A be a service that depends on another service B. When A can gracefully handle failures and restarts of B, use ``` wants = [ "B.service" ]; after = [ "B.service" ]; ``` instead of ``` requires = [ "B.service" ]; after = [ "B.service" ]; ``` in the definition of A. This way, A keeps running when B is stopped or restarted after a failure. With `requires`, A is instead stopped when B is stopped or restarted due to a failure. This brings two benefits: 1. Improved uptime Examples: - RTL keeps running when one lightning node has failed - btcpayserver keeps running and accepting on-chain payments when the lightning node has crashed 2. Avoids a systemd bug where depending units (`A.service` in the above example) are not restarted when their dependency fails (issue github/systemd#18856, no full link to avoid spamming the issue). In real world nix-bitcoin deployments, this issue was only likely to appear when clightning failed during activation, causing depending units (like `RTL`) to stop and not be restarted. All services depending on `clightning` have now been changed to use `wants`, thereby avoiding the bug. Services `electrs` and `lightning-loop` fail when their respective dependencies stop, so these services have not been changed. I also haven't changed services `joinmarket` and `joinmarket-yieldgenerator`. Further manual testing is needed to determine if they can be switched to `wants`. --- modules/btcpayserver.nix | 16 +++++++++------- modules/clightning-rest.nix | 2 +- modules/fulcrum.nix | 2 +- modules/liquid.nix | 2 +- modules/mempool.nix | 7 ++++--- modules/rtl.nix | 6 +++--- test/tests.py | 1 - 7 files changed, 19 insertions(+), 17 deletions(-) diff --git a/modules/btcpayserver.nix b/modules/btcpayserver.nix index 97bbc87..a84b5a5 100644 --- a/modules/btcpayserver.nix +++ b/modules/btcpayserver.nix @@ -171,8 +171,9 @@ in { ''; in rec { wantedBy = [ "multi-user.target" ]; - requires = [ "bitcoind.service" "postgresql.service" ] ++ optional cfg.btcpayserver.lbtc "liquidd.service"; - after = requires ++ [ "nix-bitcoin-secrets.target" ]; + requires = [ "postgresql.service" ]; + wants = [ "bitcoind.service" ] ++ optional cfg.btcpayserver.lbtc "liquidd.service"; + after = requires ++ wants ++ [ "nix-bitcoin-secrets.target" ]; preStart = '' install -m 600 ${configFile} '${cfg.nbxplorer.dataDir}/settings.config' { @@ -223,11 +224,12 @@ in { lbtcexplorerurl=${nbExplorerUrl} lbtcexplorercookiefile=${nbExplorerCookie} ''); - in let self = { + in rec { wantedBy = [ "multi-user.target" ]; - requires = [ "nbxplorer.service" "postgresql.service" ] - ++ optional (cfg.btcpayserver.lightningBackend != null) "${cfg.btcpayserver.lightningBackend}.service"; - after = self.requires; + requires = [ "postgresql.service" ]; + wants = [ "nbxplorer.service" ] + ++ optional (cfg.btcpayserver.lightningBackend != null) "${cfg.btcpayserver.lightningBackend}.service"; + after = requires ++ wants; serviceConfig = nbLib.defaultHardening // { ExecStart = '' ${cfg.btcpayserver.package}/bin/btcpayserver --conf=${configFile} \ @@ -244,7 +246,7 @@ in { } // nbLib.allowedIPAddresses cfg.btcpayserver.tor.enforce; startLimitIntervalSec = 30; startLimitBurst = 10; - }; in self; + }; users.users.${cfg.nbxplorer.user} = { isSystemUser = true; diff --git a/modules/clightning-rest.nix b/modules/clightning-rest.nix index c15ecdb..7466640 100644 --- a/modules/clightning-rest.nix +++ b/modules/clightning-rest.nix @@ -75,7 +75,7 @@ in { systemd.services.clightning-rest = mkIf cfg.enable { wantedBy = [ "multi-user.target" ]; - requires = [ "clightning.service" ]; + wants = [ "clightning.service" ]; after = [ "clightning.service" ]; path = [ pkgs.openssl ]; environment.CL_REST_STATE_DIR = cfg.dataDir; diff --git a/modules/fulcrum.nix b/modules/fulcrum.nix index 4dc06fc..4ed4fe8 100644 --- a/modules/fulcrum.nix +++ b/modules/fulcrum.nix @@ -111,7 +111,7 @@ in { systemd.services.fulcrum = { wantedBy = [ "multi-user.target" ]; - requires = [ "bitcoind.service" ]; + wants = [ "bitcoind.service" ]; after = [ "bitcoind.service" "nix-bitcoin-secrets.target" ]; preStart = '' { diff --git a/modules/liquid.nix b/modules/liquid.nix index d1daa33..f7716de 100644 --- a/modules/liquid.nix +++ b/modules/liquid.nix @@ -255,7 +255,7 @@ in { ]; systemd.services.liquidd = { - requires = [ "bitcoind.service" ]; + wants = [ "bitcoind.service" ]; after = [ "bitcoind.service" "nix-bitcoin-secrets.target" ]; wantedBy = [ "multi-user.target" ]; preStart = '' diff --git a/modules/mempool.nix b/modules/mempool.nix index 67382da..a74d513 100644 --- a/modules/mempool.nix +++ b/modules/mempool.nix @@ -275,10 +275,11 @@ in { }; }; - systemd.services.mempool = { + systemd.services.mempool = rec { wantedBy = [ "multi-user.target" ]; - requires = [ "${cfg.electrumServer}.service" ]; - after = [ "${cfg.electrumServer}.service" "mysql.service" ]; + requires = [ "mysql.service" ]; + wants = [ "${cfg.electrumServer}.service" ]; + after = requires ++ wants; preStart = '' mkdir -p '${cacheDir}/cache' <${configFile} sed \ diff --git a/modules/rtl.nix b/modules/rtl.nix index 53a3453..60a3bca 100644 --- a/modules/rtl.nix +++ b/modules/rtl.nix @@ -190,9 +190,9 @@ in { systemd.services.rtl = rec { wantedBy = [ "multi-user.target" ]; - requires = optional cfg.nodes.clightning.enable "clightning.service" ++ - optional cfg.nodes.lnd.enable "lnd.service"; - after = requires ++ [ "nix-bitcoin-secrets.target" ]; + wants = optional cfg.nodes.clightning.enable "clightning.service" ++ + optional cfg.nodes.lnd.enable "lnd.service"; + after = wants ++ [ "nix-bitcoin-secrets.target" ]; environment.RTL_CONFIG_PATH = cfg.dataDir; environment.DB_DIRECTORY_PATH = cfg.dataDir; serviceConfig = nbLib.defaultHardening // { diff --git a/test/tests.py b/test/tests.py index fb0fe05..7716a58 100644 --- a/test/tests.py +++ b/test/tests.py @@ -386,7 +386,6 @@ def _(): @test("restart-bitcoind") def _(): # Sanity-check system by restarting bitcoind. - # This also restarts all services depending on bitcoind. succeed("systemctl restart bitcoind") @test("regtest")