#!/usr/bin/env bash set -euo pipefail BINARY="${BINARY:-/opt/lingniu-go-native/current/stats-backfill}" DATE_FROM="${DATE_FROM:-}" DATE_TO="${DATE_TO:-}" PARALLEL="${PARALLEL:-4}" APPLY=false WORK_DIR="" usage() { cat <<'USAGE' Usage: replay-pure-hydrogen-mileage.sh --date-from YYYY-MM-DD --date-to YYYY-MM-DD [options] Options: --apply Write the rebuilt daily mileage rows. Default is dry-run. --parallel N Concurrent VIN workers. Default: 4. --binary PATH stats-backfill binary path. --work-dir PATH Keep VIN lists and per-VIN logs in this directory. USAGE } if [[ "${1:-}" == "--worker" ]]; then vin="$2" dry_run="$3" log_dir="$4" env \ BACKFILL_METHOD=scan \ BACKFILL_DRY_RUN="$dry_run" \ BACKFILL_DATE_FROM="$DATE_FROM" \ BACKFILL_DATE_TO="$DATE_TO" \ BACKFILL_PROTOCOLS=GB32960 \ BACKFILL_VINS="$vin" \ BACKFILL_PROGRESS_EVERY=100000 \ "$BINARY" >"$log_dir/$vin.log" 2>&1 printf 'completed vin=%s\n' "$vin" exit 0 fi while (($#)); do case "$1" in --date-from) DATE_FROM="$2"; shift 2 ;; --date-to) DATE_TO="$2"; shift 2 ;; --parallel) PARALLEL="$2"; shift 2 ;; --binary) BINARY="$2"; shift 2 ;; --work-dir) WORK_DIR="$2"; shift 2 ;; --apply) APPLY=true; shift ;; -h|--help) usage; exit 0 ;; *) echo "unknown argument: $1" >&2; usage >&2; exit 2 ;; esac done if [[ ! "$DATE_FROM" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ || ! "$DATE_TO" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ ]]; then echo "--date-from and --date-to are required" >&2 exit 2 fi if [[ ! "$PARALLEL" =~ ^[1-9][0-9]*$ ]]; then echo "--parallel must be a positive integer" >&2 exit 2 fi if [[ ! -x "$BINARY" ]]; then echo "stats-backfill is not executable: $BINARY" >&2 exit 2 fi if [[ -z "$WORK_DIR" ]]; then WORK_DIR="$(mktemp -d /tmp/pure-hydrogen-replay.XXXXXX)" else mkdir -p "$WORK_DIR" fi LOG_DIR="$WORK_DIR/logs" mkdir -p "$LOG_DIR" hydrogen_vins="$WORK_DIR/hydrogen-vins.txt" active_vins="$WORK_DIR/active-gb32960-vins.txt" target_vins="$WORK_DIR/target-vins.txt" pending_vins="$WORK_DIR/pending-vins.txt" BACKFILL_LIST_HYDROGEN_VINS=true "$BINARY" | LC_ALL=C sort -u >"$hydrogen_vins" env \ BACKFILL_LIST_ACTIVE_VINS=true \ BACKFILL_DATE_FROM="$DATE_FROM" \ BACKFILL_DATE_TO="$DATE_TO" \ BACKFILL_PROTOCOLS=GB32960 \ "$BINARY" | LC_ALL=C sort -u >"$active_vins" comm -12 "$hydrogen_vins" "$active_vins" >"$target_vins" target_count="$(wc -l <"$target_vins" | tr -d ' ')" : >"$pending_vins" while IFS= read -r vin; do if [[ -f "$LOG_DIR/$vin.log" ]] && grep -q 'stats backfill complete' "$LOG_DIR/$vin.log"; then continue fi echo "$vin" >>"$pending_vins" done <"$target_vins" pending_count="$(wc -l <"$pending_vins" | tr -d ' ')" dry_run=true if [[ "$APPLY" == true ]]; then dry_run=false fi printf 'pure-hydrogen replay: date=%s..%s vins=%s pending=%s parallel=%s dry_run=%s work_dir=%s\n' \ "$DATE_FROM" "$DATE_TO" "$target_count" "$pending_count" "$PARALLEL" "$dry_run" "$WORK_DIR" if [[ "$pending_count" == "0" ]]; then printf 'pure-hydrogen replay complete: vins=%s logs=%s\n' "$target_count" "$LOG_DIR" exit 0 fi export BINARY DATE_FROM DATE_TO set +e xargs -I '{}' -P "$PARALLEL" "$0" --worker '{}' "$dry_run" "$LOG_DIR" <"$pending_vins" xargs_status=$? set -e failed_vins="$WORK_DIR/failed-vins.txt" : >"$failed_vins" while IFS= read -r vin; do if [[ ! -f "$LOG_DIR/$vin.log" ]] || ! grep -q 'stats backfill complete' "$LOG_DIR/$vin.log"; then echo "$vin" >>"$failed_vins" fi done <"$target_vins" if [[ "$xargs_status" != "0" || -s "$failed_vins" ]]; then echo "replay incomplete; inspect $failed_vins and $LOG_DIR" >&2 exit 1 fi printf 'pure-hydrogen replay complete: vins=%s logs=%s\n' "$target_count" "$LOG_DIR"