feat: Implement update scheduling with dynamic timing and update buffer management

This commit is contained in:
2026-04-17 18:58:10 +02:00
parent 061f975727
commit 09cea7a0f8
2 changed files with 98 additions and 2 deletions
+24 -2
View File
@@ -191,7 +191,29 @@ setup_scheduled_jobs() {
fi
local update_line backup_line
update_line="0 3 * * * cd $SCRIPT_DIR && ./update.sh >> $SCRIPT_DIR/logs/update.log 2>&1"
local slot_seed slot_hash slot_bucket slot_hour slot_minute
local update_window_minutes update_window_hours
update_window_minutes="${INVENTAR_UPDATE_WINDOW_MINUTES:-120}"
if ! [[ "$update_window_minutes" =~ ^[0-9]+$ ]]; then
update_window_minutes="120"
fi
if [ "$update_window_minutes" -lt 15 ]; then
update_window_minutes="15"
fi
update_window_hours=$(( (update_window_minutes + 59) / 60 ))
if [ "$update_window_hours" -lt 1 ]; then
update_window_hours=1
fi
slot_seed="$(cat /etc/machine-id 2>/dev/null || hostname)|${INVENTAR_INSTANCE_ID:-${HOSTNAME:-unknown}}|$SCRIPT_DIR|nightly-update"
slot_hash="$(printf '%s' "$slot_seed" | sha256sum | awk '{print $1}')"
slot_bucket=$((16#${slot_hash:0:8} % update_window_minutes))
slot_hour=$((3 + (slot_bucket / 60)))
slot_minute=$((slot_bucket % 60))
update_line="$slot_minute $slot_hour * * * cd $SCRIPT_DIR && INVENTAR_UPDATE_MODE=auto ./update.sh >> $SCRIPT_DIR/logs/update.log 2>&1"
backup_line="30 2 * * * cd $SCRIPT_DIR && ./backup.sh --mode auto >> $SCRIPT_DIR/logs/backup.log 2>&1"
local existing_cron
@@ -212,7 +234,7 @@ setup_scheduled_jobs() {
fi
echo "Nightly backup scheduled at 02:30"
echo "Nightly auto-update scheduled at 03:00"
printf 'Nightly auto-update scheduled at %02d:%02d (deterministic instance slot, %s-minute window)\n' "$slot_hour" "$slot_minute" "$update_window_minutes"
}
ensure_tls_certificates() {
+74
View File
@@ -15,6 +15,9 @@ APP_IMAGE_ASSET_PREFIX="inventarsystem-image-"
ENV_FILE="$PROJECT_DIR/.docker-build.env"
APP_IMAGE_REPO="ghcr.io/aiirondev/legendary-octo-garbanzo"
DIST_DIR="$PROJECT_DIR/dist"
LOCK_FILE="$PROJECT_DIR/.update.lock"
DEFAULT_UPDATE_BUFFER_MINUTES="${INVENTAR_UPDATE_BUFFER_MINUTES:-90}"
mkdir -p "$LOG_DIR"
chmod 777 "$LOG_DIR" 2>/dev/null || true
@@ -23,6 +26,74 @@ log_message() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}
safe_int() {
local raw="$1"
if [[ "$raw" =~ ^[0-9]+$ ]]; then
echo "$raw"
else
echo "0"
fi
}
acquire_update_lock() {
exec 9>"$LOCK_FILE"
if ! flock -n 9; then
log_message "Another update process is already running. Exiting."
exit 0
fi
}
compute_update_buffer_seconds() {
if [ "${INVENTAR_SKIP_UPDATE_BUFFER:-0}" = "1" ]; then
echo "0"
return 0
fi
# Manual interactive runs should not wait by default.
if [ -t 1 ] && [ "${INVENTAR_FORCE_UPDATE_BUFFER:-0}" != "1" ]; then
echo "0"
return 0
fi
local explicit_seconds
explicit_seconds="$(safe_int "${INVENTAR_UPDATE_BUFFER_SECONDS:-0}")"
if [ "$explicit_seconds" -gt 0 ]; then
echo "$explicit_seconds"
return 0
fi
local window_minutes window_seconds
window_minutes="$(safe_int "$DEFAULT_UPDATE_BUFFER_MINUTES")"
if [ "$window_minutes" -le 0 ]; then
echo "0"
return 0
fi
window_seconds=$((window_minutes * 60))
local machine_id instance_id seed hash_hex hash_dec
machine_id="$(cat /etc/machine-id 2>/dev/null || hostname)"
instance_id="${INVENTAR_INSTANCE_ID:-${HOSTNAME:-unknown}}"
seed="$machine_id|$instance_id|$PROJECT_DIR|update-buffer"
hash_hex="$(printf '%s' "$seed" | sha256sum | awk '{print $1}')"
hash_dec=$((16#${hash_hex:0:8}))
echo $((hash_dec % window_seconds))
}
apply_update_buffer_if_needed() {
local delay_seconds
delay_seconds="$(compute_update_buffer_seconds)"
if [ "$delay_seconds" -le 0 ]; then
log_message "Update buffer: no delay applied"
return 0
fi
log_message "Update buffer active: delaying start by ${delay_seconds}s to reduce cross-instance peak load"
sleep "$delay_seconds"
}
require_cmd() {
if ! command -v "$1" >/dev/null 2>&1; then
log_message "ERROR: Required command not found: $1"
@@ -395,6 +466,9 @@ verify_stack_health() {
}
main() {
acquire_update_lock
apply_update_buffer_if_needed
ensure_runtime_dependencies
ensure_tls_certificates
ensure_nginx_config_mount_source