Stop the media seed from holding the onboard, and therefore the partnership, open for weeks

A first seed is ~28 TB behind a 12.5 MB/s bwlimit, and it ran inline as Step 9d, so the
phase-2 flag every status reader depends on was written only after it finished.
This commit is contained in:
Gmer4Lfe
2026-08-17 07:40:00 -04:00
parent 9d2610a911
commit ad623353bc
6 changed files with 466 additions and 61 deletions
+69 -61
View File
@@ -34,16 +34,17 @@
# Step 9b: Webhook setup — register download webhook in arrs on both servers
# Step 9c: Arm sync gates — open RSYNC/CONF_SYNC/ARR_SYNC in master.conf, which the
# template ships closed so a fresh node cannot sync early.
# Ahead of the seed because the seed is itself an rsync and
# Tier 1 stops every rsync, including that one
# Step 9d: Media seed — rsync all DAILY_SYNC_SHARES to mirror (--seed)
# prevents arrs treating every file as missing after bootstrap
# Still ahead of the Step 13 seed, which is itself an rsync
# and dies at the Tier 1 gate if this has not run
# Step 9e: Webhook listener — start listener on mirror (runs continuously, no reboot needed)
# Step 10: Conf push — push master.conf + setup state to all listed hosts
# Step 11: Service discovery — conf_populate.sh on the mirror, last, once the stacks it
# would discover are actually deployed there
# Step 12: Container grouping — file our containers on the mirror under "<OwnerShort>-Fallback",
# icon resolved here and passed over: the mirror has no Emby key
# Step 13: Media seed — dispatch Rsync/media_seed.sh detached, after the phase flag
# is written. It is a multi-week transfer and must never be
# the thing standing between an onboard and its own summary
#
# ==============================================================================================
# DESIGN PRINCIPLES
@@ -159,7 +160,7 @@
# Skip webhook registration in arrs (Step 9b)
#
# Partnership/partnership_onboard.sh --skip-media-seed
# Skip initial media share rsync to mirror (Step 9d)
# Skip dispatching the background media seed (Step 13)
# Use when mirror already has files or you want to seed manually
#
# Partnership/partnership_onboard.sh --skip-webhook-listener
@@ -489,8 +490,6 @@ SERVICES_FAILED=0
ONBOARD_OK=false
ARR_SYNC_OK=false
WEBHOOK_SETUP_OK=false
MEDIA_SEED_OK=false
MEDIA_SEED_COUNT=0
WEBHOOK_LISTENER_OK=false
MASTER_PUSH_OK=false
@@ -931,57 +930,6 @@ else
unset _master_conf
fi
# ── Step 9d: Seed media shares on mirror ─────────────────────────────────────────────────────
# arr_sync.sh bootstrapped the databases — mirror's arrs now know about all content but
# have no files on disk. Without this rsync, every imported item looks missing and arrs
# will immediately queue searches. --seed skips the empty-remote guard and does a clean push.
echo ""
echo "━━━ Step 9d — Media Share Seed ━━━"
# Read the gate back off disk rather than trusting the value sourced at startup: Step 9c has
# just rewritten master.conf, and each rsync.sh below is a separate process that will source
# the file fresh. A closed gate here means every share would exit 0 having moved nothing, so
# say so once and skip, instead of counting fourteen no-ops as fourteen successes.
#
# The trailing comment is cut before the value is read. master.conf writes this gate as
# RSYNC_ENABLED=true # Tier 1 — global gate, overrides everything below
# so stopping at `cut -d= -f2` and squeezing whitespace yields "true#Tier1—globalgate,…",
# which is not "true" — and the seed would then skip itself on every single run, including
# the ones where the gate is open.
_rsync_gate=$(grep -m1 -E '^[[:space:]]*RSYNC_ENABLED=' "$SCRIPTS_ROOT/Configurations/master.conf" 2>/dev/null \
| cut -d= -f2- | cut -d'#' -f1 | tr -d '"'"'" | tr -d '[:space:]')
if [[ "$SKIP_MEDIA_SEED" == true ]]; then
warn "Skipping (--skip-media-seed)"
elif [[ "$DRY_RUN" == false && "$_rsync_gate" != "true" ]]; then
warn "RSYNC_ENABLED is '$_rsync_gate' — skipping media seed, rsync.sh would move nothing"
warn "Arm it and re-run: Rsync/rsync.sh <share> --seed"
elif [[ "${#DAILY_SYNC_SHARES[@]}" -eq 0 ]]; then
warn "DAILY_SYNC_SHARES empty for $MY_ID — skipping media seed"
warn "Configure HOST${MY_ID: -1}_DAILY_SYNC_SHARES in host${MY_ID: -1}.conf and run Rsync/rsync.sh --seed manually"
else
echo " Seeding ${#DAILY_SYNC_SHARES[@]} share(s) to $MIRROR — this may take a while"
_rsync_script="$SCRIPTS_ROOT/Rsync/rsync.sh"
_seed_flags=(--seed)
[[ "$DRY_RUN" == true ]] && _seed_flags+=(--dry-run)
[[ "$ENABLE_LOGGING" == true ]] && _seed_flags+=(--log)
for _share in "${DAILY_SYNC_SHARES[@]}"; do
echo " Seeding: $_share"
if bash "$_rsync_script" "$_share" "${_seed_flags[@]}"; then
(( MEDIA_SEED_COUNT++ )) || true
else
warn " Seed failed for $_share — re-run: Rsync/rsync.sh $_share --seed"
fi
done
if [[ "$MEDIA_SEED_COUNT" -gt 0 ]]; then
echo "Media seed complete — ${MEDIA_SEED_COUNT}/${#DAILY_SYNC_SHARES[@]} share(s) ✅"
MEDIA_SEED_OK=true
else
warn "Media seed: no shares completed — check errors above"
fi
unset _rsync_script _seed_flags _share
fi
# ── Step 9e: Start webhook listener on mirror ─────────────────────────────────────────────────
# Listener is in ARRAY_START_SCRIPTS so it starts on next boot, but the mirror's array is
# already running — kick it now so events are captured immediately after onboard.
@@ -1121,6 +1069,66 @@ fi
# ── Write Phase 2 completion state ────────────────────────────────────────────────────────────
[[ "$ONBOARD_OK" == true && "$DRY_RUN" == false ]] && write_onboard_phase "$MIRROR_ID" 2
# ── Step 13: Dispatch the media seed ──────────────────────────────────────────────────────────
# Last, detached, and after the phase flag is already on disk — see the header of
# Rsync/media_seed.sh for why. Briefly: on HOST1 this is thirteen shares and ~28 TB behind a
# 12.5 MB/s bwlimit, so inline it held this script open for weeks. Everything below it waited,
# including write_onboard_phase above, so the owner's card stayed on "Waiting for HOST2 to
# install Varaverk" and the mirror's checklist on "1 required item left: Partnership" for the
# entire transfer, describing a partnership that was already established. The onboard job
# record also stayed "running", which run_job.sh's already-running guard reads as a reason to
# refuse every later onboard.
#
# setsid, not nohup + &: the seed must survive this script exiting and must not share a process
# group with it, or stopping the onboard takes the transfer down with it.
echo ""
echo "━━━ $ICON_SYNC Step 13 — Media Share Seed (dispatch) ━━━"
MEDIA_SEED_DISPATCHED=false
_seed_job="Rsync/media_seed.sh"
_seed_script="$SCRIPTS_ROOT/Rsync/media_seed.sh"
_runner="$SCRIPTS_ROOT/Plugin/$PLATFORM/run_job.sh"
if [[ "$SKIP_MEDIA_SEED" == true ]]; then
warn "Skipping (--skip-media-seed)"
elif [[ "$ONBOARD_OK" == false ]]; then
warn "Skipping — onboard did not complete"
elif [[ "$DRY_RUN" == true ]]; then
warn "DRY RUN — would dispatch $_seed_job"
elif [[ ! -f "$_seed_script" || ! -f "$_runner" ]]; then
warn "Seed runner not found — run manually: bash $_seed_script"
else
_seed_flags=()
[[ "$ENABLE_LOGGING" == true ]] && _seed_flags+=(--log)
setsid bash "$_runner" "$_seed_job" "$_seed_script" "${_seed_flags[@]}" \
>/dev/null 2>&1 < /dev/null &
disown 2>/dev/null || true
# Confirm the runner actually took the job rather than reporting the launch. run_job.sh
# writes its stat file before exec'ing the script, so a fresh "running" record with a live
# pid is the difference between dispatched and merely attempted.
_seed_stat="/var/log/varaverk/Rsync/media_seed.json"
for _i in 1 2 3 4 5 6 7 8 9 10; do
if [[ -f "$_seed_stat" ]] \
&& grep -q '"status":"running"' "$_seed_stat" 2>/dev/null \
&& (( $(date +%s) - $(stat -c %Y "$_seed_stat") < 60 )); then
MEDIA_SEED_DISPATCHED=true
break
fi
sleep 1
done
unset _seed_stat _i _seed_flags
if [[ "$MEDIA_SEED_DISPATCHED" == true ]]; then
echo "Seed running as job $_seed_job"
echo " ${#DAILY_SYNC_SHARES[@]} share(s) — watch it on the Scheduler tab, not here"
echo " A first full seed runs for days. The partnership is live now; this only fills disks."
else
warn "Seed did not start — run manually: bash $_seed_script"
fi
fi
unset _seed_job _seed_script _runner
# ── Summary ───────────────────────────────────────────────────────────────────────────────────
END=$(date +%s)
echo ""
@@ -1145,13 +1153,13 @@ echo " Step 8 — Onboard: $(_ok "$ONBOARD_OK")"
echo " Step 9 — Arr bootstrap: $( [[ "$SKIP_ARR_SYNC" == true || "$ONBOARD_OK" == false ]] && echo "skipped" || echo "$(_ok "$ARR_SYNC_OK")" )"
echo " Step 9b — Webhook setup: $(_skip "$SKIP_WEBHOOK_SETUP" "$WEBHOOK_SETUP_OK")"
echo " Step 9c — Arm sync gates: $( [[ "$SKIP_ARM" == true ]] && echo "skipped (--no-arm)" || { [[ "$ONBOARD_OK" == false ]] && echo "skipped" || echo "$(_ok "$ARM_OK")"; } )"
echo " Step 9d — Media seed: $( [[ "$SKIP_MEDIA_SEED" == true ]] && echo "skipped" \
|| { [[ "$DRY_RUN" == false && "${_rsync_gate:-}" != "true" ]] && echo "skipped (rsync gate closed)" \
|| echo "${MEDIA_SEED_COUNT}/${#DAILY_SYNC_SHARES[@]} shares $(_ok "$MEDIA_SEED_OK")"; } )"
echo " Step 9e — Webhook listener: $(_skip "$SKIP_WEBHOOK_LISTENER" "$WEBHOOK_LISTENER_OK")"
echo " Step 10 — Conf push: $( [[ "$ONBOARD_OK" == false ]] && echo "skipped" || echo "$(_ok "$MASTER_PUSH_OK")" )"
echo " Step 11 — Discovery: $( [[ "$POPULATE_OK" == skipped ]] && echo "skipped (unreachable)" || _ok "$POPULATE_OK" )"
echo " Step 12 — Grouping: $( [[ "$FOLDER_OK" == skipped ]] && echo "skipped" || _ok "$FOLDER_OK" )"
echo " Step 13 — Media seed: $( [[ "$SKIP_MEDIA_SEED" == true ]] && echo "skipped" \
|| { [[ "$MEDIA_SEED_DISPATCHED" == true ]] && echo "dispatched — runs in background ✅" \
|| echo "not dispatched ❌"; } )"
echo ""
if [[ "$ONBOARD_OK" == true ]]; then