diff --git a/nix/packages/default.nix b/nix/packages/default.nix index b7ad2b205..2228bfd11 100644 --- a/nix/packages/default.nix +++ b/nix/packages/default.nix @@ -5,6 +5,7 @@ ./postgres-env.nix ./site-env.nix ./extension-catalog.nix + ./nix-dl.nix ]; perSystem = { diff --git a/nix/packages/extension-catalog.nix b/nix/packages/extension-catalog.nix index d8d559121..7de8d0252 100644 --- a/nix/packages/extension-catalog.nix +++ b/nix/packages/extension-catalog.nix @@ -152,13 +152,14 @@ name = "site-extensions-update"; runtimeInputs = [ self'.packages.site-extensions-resolve + self'.packages.nix-dl pkgs.nix ]; text = '' manifest="''${1:?Usage: $0 path-to/pg-extensions.json}" profile="''${NIX_PROFILE:-/nix/var/nix/profiles/site-extensions}" readarray -t paths < <(site-extensions-resolve "$manifest") - nix-store -r --option stalled-download-timeout 120 "''${paths[@]}" >/dev/null + nix-dl "''${paths[@]}" nix-env --profile "$profile" --install "''${paths[@]}" --remove-all ''; }; diff --git a/nix/packages/nix-dl.nix b/nix/packages/nix-dl.nix new file mode 100644 index 000000000..c193112d3 --- /dev/null +++ b/nix/packages/nix-dl.nix @@ -0,0 +1,36 @@ +# Download nix store paths with timeout and retry. +{ + perSystem = + { pkgs, ... }: + { + packages.nix-dl = pkgs.writeShellApplication { + name = "nix-dl"; + runtimeInputs = [ + pkgs.coreutils + pkgs.nix + ]; + text = '' + # nix-store -r can stall indefinitely: https://github.com/NixOS/nix/issues/8758 + timeout_="''${NIX_DL_TIMEOUT:-120s}" + kill_grace="''${NIX_DL_KILL_GRACE:-10s}" + attempts="''${NIX_DL_ATTEMPTS:-3}" + + for path in "$@"; do + ok="false" + for attempt in $(seq 1 "$attempts"); do + if timeout -k "$kill_grace" "$timeout_" nix-store -r "$path" >/dev/null; then + ok="true" + break + fi + if [ "$attempt" -lt "$attempts" ]; then + echo "WARNING: nix-store -r attempt $attempt/$attempts for $path failed or stalled (>=$timeout_ + up to $kill_grace kill grace); retrying" >&2 + else + echo "ERROR: nix-store -r failed after $attempts attempts for $path" >&2 + fi + done + [ "$ok" = "true" ] || exit 1 + done + ''; + }; + }; +}