From 976d8d84d73ab4a23730215514badd0083e53e7f Mon Sep 17 00:00:00 2001 From: Gmer4Lfe Date: Fri, 17 Jul 2026 01:23:31 -0400 Subject: [PATCH] Add OPERATIONAL SAFEGUARDS headers, skip prefill during active rescans arr_full_rescan.sh, arr_cache_prefill.sh, and arr_rescan_monitor.sh were missing the standard SAFEGUARDS header section other Arrs_Stack/Tools scripts have. Also: arr_cache_prefill.sh now checks for an active rescan before fetching, instead of doing a live fetch that arr_cache_write() would just refuse to persist anyway -- avoids wasted API calls every 30min during a long rescan. arr_rescan_monitor.sh was also missing an actual root check despite writing cache files; added it to match convention rather than just document a safeguard that wasn't there. --- Arrs_Stack/arr_cache_prefill.sh | 49 +++++++++++++++++++++++++++++---- Arrs_Stack/arr_full_rescan.sh | 18 ++++++++++++ Tools/arr_rescan_monitor.sh | 19 +++++++++++++ 3 files changed, 80 insertions(+), 6 deletions(-) diff --git a/Arrs_Stack/arr_cache_prefill.sh b/Arrs_Stack/arr_cache_prefill.sh index 5f2eafb..9956c6e 100755 --- a/Arrs_Stack/arr_cache_prefill.sh +++ b/Arrs_Stack/arr_cache_prefill.sh @@ -6,11 +6,18 @@ # PURPOSE # ───────────────────────────────────────────────────────────────────────────── # Populates the shared tracked-data cache (see arr_get_tracked_data() in common.sh) for -# Lidarr, Sonarr, and Radarr once at array start, before any other script needs it. Without -# this, each arr's cache stays cold from boot until whichever script happens to touch that -# arr first writes through — which could be hours, depending on the daily schedule. One-shot: -# runs and exits. Originally Lidarr-only (lidarr_cache_prefill.sh, 2026-07-16), generalized -# the same day to cover all three arrs once the cache mechanism itself was generalized. +# Lidarr, Sonarr, and Radarr. Without this, each arr's cache stays cold until whichever +# script happens to touch that arr first writes through — which could be hours, depending +# on the daily schedule. Originally Lidarr-only (lidarr_cache_prefill.sh, 2026-07-16), +# generalized the same day to cover all three arrs once the cache mechanism itself was +# generalized. +# +# Runs on two schedules (2026-07-17): once at array start (closes the cold-boot gap, 10min +# wait ceiling for slow-starting containers) and again every 30min via +# CRITICAL_MAINTENANCE_SCRIPTS with a 1min wait ceiling (ARR_PREFILL_WAIT_MINUTES=1 override) +# — a live fetch+write takes seconds, so there's no reason to tolerate the boot-time wait on +# a recurring job. This is what keeps the cache-first consumers' data reliably under 30min +# old instead of only refreshing whenever some other script happens to write through. # # ============================================================================================== # OPERATIONAL MODEL @@ -23,6 +30,22 @@ # An arr not configured on this host (e.g. Lidarr is HOST1-only) is skipped cleanly. # # ============================================================================================== +# OPERATIONAL SAFEGUARDS +# ============================================================================================== +# +# Root required — chown-free here, but matches convention across Arrs_Stack/ +# jq required — skips the whole run cleanly (not fatal) if jq is missing +# acquire_lock — prevents two invocations of this script overlapping (default strict +# mode) — matters if the boot-time run is still waiting on a slow +# container when the first 30min critical-tier tick fires +# Reachability retry — tolerates a slow-starting container up to ARR_PREFILL_WAIT_MINUTES; +# never fatal if one never comes up, that arr's cache just stays cold +# Active-rescan check — skips an arr this cycle if a rescan-type command is running, instead +# of a live fetch arr_cache_write() would refuse to persist anyway +# (2026-07-17) — avoids wasted API calls during a long rescan +# Per-arr isolation — one arr failing or timing out never blocks or fails the others +# +# ============================================================================================== # CONFIGURATION # ============================================================================================== # @@ -33,7 +56,10 @@ # All aliased by detect_hosts() # # master.conf -# ARR_PREFILL_WAIT_MINUTES — how long to retry reaching each arr before giving up on it (default 10) +# ARR_PREFILL_WAIT_MINUTES — how long to retry reaching each arr before giving up on it +# (default 10). The CRITICAL_MAINTENANCE_SCRIPTS entry overrides this to 1 via parse_args' +# VAR=VAL mechanism for the 30min recurring run — the 10min default is sized for cold boot, +# not a job that fires every half hour. # # ============================================================================================== @@ -78,6 +104,17 @@ _prefill_one() { (( waited += 15 )) done + # Skip cleanly if a rescan-type command is already active — arr_cache_write() below + # would refuse to persist a mid-rescan snapshot anyway (2026-07-17 guard), so fetching + # it live first would just be a wasted API call every time this fires during a long + # rescan. Matches the same check arr_full_rescan.sh and the cleanup scripts already do. + local active_cmd + active_cmd=$(arr_active_rescan_command "$arr_type" "$url" "$api_key" "$api_version") + if [[ -n "$active_cmd" ]]; then + info "${arr_type^} mid-rescan ($active_cmd) — skipping this cycle, cache stays as-is" + return 0 + fi + local endpoint="${ARR_LIBRARY_ENDPOINT[$arr_type]:-}" if [[ -z "$endpoint" ]]; then warn "No library endpoint known for ${arr_type} — skipping" diff --git a/Arrs_Stack/arr_full_rescan.sh b/Arrs_Stack/arr_full_rescan.sh index d42d4eb..13ed4ae 100755 --- a/Arrs_Stack/arr_full_rescan.sh +++ b/Arrs_Stack/arr_full_rescan.sh @@ -20,6 +20,24 @@ # and running them concurrently would just contend for the same disk I/O for no benefit. # # ============================================================================================== +# OPERATIONAL SAFEGUARDS +# ============================================================================================== +# +# Root required — required for consistency across Arrs_Stack/, no direct fs writes here +# acquire_lock "wait" — waits for a prior run to finish rather than skipping or colliding; +# a full-library rescan across three arrs can run long, worth queuing +# behind rather than silently no-op'ing +# Reachability check — check_api before touching an arr; unreachable → skip that arr only +# Active-rescan check — skips triggering a NEW rescan if one's already active on that arr +# (manual trigger, another script) — never stacks a duplicate scan, +# see Tools/arr_rescan_monitor.sh for catching up that arr's cache +# once the pre-existing scan finishes instead of waiting for next week +# Sequential only — never runs two arrs' rescans in parallel; each is a heavy full-disk +# walk and concurrent walks would just contend for the same disk I/O +# Per-arr isolation — one arr failing, timing out, or being skipped never blocks the others +# --dry-run mode — reports which arrs would be rescanned, triggers nothing +# +# ============================================================================================== # CONFIGURATION # ============================================================================================== # diff --git a/Tools/arr_rescan_monitor.sh b/Tools/arr_rescan_monitor.sh index abace99..8fd92a9 100755 --- a/Tools/arr_rescan_monitor.sh +++ b/Tools/arr_rescan_monitor.sh @@ -19,6 +19,19 @@ # this for scans it triggers itself; this tool covers everything else. # # ============================================================================================== +# OPERATIONAL SAFEGUARDS +# ============================================================================================== +# +# Root required — matches convention across Arrs_Stack/Tools/, writes cache files +# Arg validation — arr_type must be lidarr/sonarr/radarr, usage error otherwise +# Timeout, never waits forever — default 2h ceiling, override via second positional arg; +# on timeout, cache is left untouched rather than acted on stale +# --status mode — read-only, shows active rescan + cache age, waits/writes nothing +# --dry-run mode — shows what would be waited on, waits/writes nothing +# Triggers nothing — never starts a rescan itself, only watches one already running; +# use arr_full_rescan.sh or the arr's own UI/API to start one +# +# ============================================================================================== # RUNTIME MODES # ============================================================================================== # @@ -40,6 +53,12 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source "$SCRIPT_DIR/../load_config.sh" parse_args "$@" + +if [[ "$EUID" -ne 0 ]]; then + error "Must be run as root" + exit 1 +fi + detect_hosts ARR_TYPE="${PARSED_ARGS[0]:-}"