Files
orbit/scripts/test-schedule-backlog.sh

143 lines
6.7 KiB
Bash
Executable File

#!/bin/sh
# 在一次性 MySQL 中复现集中触发后的持久任务积压曲线。
# 样本故意以有界截止结束;退出 0 表示“预期的非零工具结果已核对”,不是任务全部完成。
set -eu
TASK_DOCKER=${DOCKER:-docker}
TASK_GO=${GO:-go}
TASK_MYSQL_IMAGE=${ORBIT_TEST_MYSQL_IMAGE:-mysql:8.4}
TASK_RUN_TIMEOUT=${ORBIT_BACKLOG_RUN_TIMEOUT:-180s}
TASK_NAME="orbit-schedule-backlog-$$"
TASK_DIR=$(mktemp -d "${TMPDIR:-/tmp}/orbit-schedule-backlog.XXXXXX")
TASK_SERVER_PID=
TASK_LOAD_PID=
cleanup() {
if [ -n "$TASK_LOAD_PID" ]; then
kill "$TASK_LOAD_PID" >/dev/null 2>&1 || true
wait "$TASK_LOAD_PID" 2>/dev/null || true
fi
if [ -n "$TASK_SERVER_PID" ]; then
kill "$TASK_SERVER_PID" >/dev/null 2>&1 || true
wait "$TASK_SERVER_PID" 2>/dev/null || true
fi
"$TASK_DOCKER" container stop "$TASK_NAME" >/dev/null 2>&1 || true
"$TASK_DOCKER" container rm "$TASK_NAME" >/dev/null 2>&1 || true
if [ "${ORBIT_TEST_KEEP_ARTIFACTS:-0}" = 1 ]; then
TASK_KEEP_DIR=${ORBIT_TEST_KEEP_ARTIFACTS_PATH:-/tmp/orbit-schedule-backlog-last}
mkdir -p "$TASK_KEEP_DIR"
for task_artifact in "$TASK_DIR"/*; do
if [ -f "$task_artifact" ]; then cp "$task_artifact" "$TASK_KEEP_DIR/"; fi
done
fi
for task_artifact in "$TASK_DIR"/*; do
if [ -f "$task_artifact" ]; then unlink "$task_artifact"; fi
done
rmdir "$TASK_DIR" 2>/dev/null || true
}
trap cleanup EXIT HUP INT TERM
umask 077
TASK_DB_PASSWORD=$(openssl rand -hex 24)
"$TASK_DOCKER" run -d --name "$TASK_NAME" \
-e MYSQL_ROOT_PASSWORD="$TASK_DB_PASSWORD" \
-e MYSQL_DATABASE=orbit_test \
-p 127.0.0.1::3306 "$TASK_MYSQL_IMAGE" >/dev/null
TASK_READY=0
for task_attempt in $(seq 1 60); do
if "$TASK_DOCKER" exec -e MYSQL_PWD="$TASK_DB_PASSWORD" "$TASK_NAME" \
mysql -uroot --protocol=tcp -e 'SELECT 1' >/dev/null 2>&1; then
TASK_READY=1
break
fi
sleep 1
done
if [ "$TASK_READY" -ne 1 ]; then
printf '%s\n' 'Disposable MySQL failed to become ready.' >&2
"$TASK_DOCKER" logs --tail 30 "$TASK_NAME" >&2 || true
exit 1
fi
TASK_DB_PORT=$("$TASK_DOCKER" port "$TASK_NAME" 3306/tcp | sed 's/.*://')
TASK_DSN="root:$TASK_DB_PASSWORD@tcp(127.0.0.1:$TASK_DB_PORT)/orbit_test"
"$TASK_GO" build -o "$TASK_DIR/orbit" ./cmd/orbit
"$TASK_GO" build -o "$TASK_DIR/orbit-migrate" ./cmd/orbit-migrate
"$TASK_GO" build -o "$TASK_DIR/orbit-admin" ./cmd/orbit-admin
(cd sdk/go && GOWORK=off "$TASK_GO" build -o "$TASK_DIR/orbit-schedule-load" ./cmd/orbit-schedule-load)
ORBIT_MYSQL_DSN="$TASK_DSN" "$TASK_DIR/orbit-migrate" up >/dev/null
ORBIT_MYSQL_DSN="$TASK_DSN" "$TASK_DIR/orbit-admin" bootstrap \
--application schedule-backlog --namespace test --environment test --queue schedule \
--worker-access --schedule-access --output "$TASK_DIR/credentials.json" >/dev/null
ORBIT_MYSQL_DSN="$TASK_DSN" ORBIT_HTTP_ADDR=127.0.0.1:0 "$TASK_DIR/orbit" >"$TASK_DIR/server.log" 2>&1 &
TASK_SERVER_PID=$!
TASK_HTTP_PORT=
for task_attempt in $(seq 1 30); do
TASK_HTTP_PORT=$(sed -n 's/.*"address":"127.0.0.1:\([0-9]*\)".*/\1/p' "$TASK_DIR/server.log" | head -n 1)
if [ -n "$TASK_HTTP_PORT" ]; then break; fi
if ! kill -0 "$TASK_SERVER_PID" 2>/dev/null; then cat "$TASK_DIR/server.log" >&2; exit 1; fi
sleep 1
done
if [ -z "$TASK_HTTP_PORT" ]; then
printf '%s\n' 'Orbit HTTP server failed to start.' >&2
exit 1
fi
query() {
"$TASK_DOCKER" exec -e MYSQL_PWD="$TASK_DB_PASSWORD" "$TASK_NAME" \
mysql -uroot --protocol=tcp --batch --skip-column-names orbit_test -e "$1"
}
: >"$TASK_DIR/curve.jsonl"
export ORBIT_URL="http://127.0.0.1:$TASK_HTTP_PORT" ORBIT_CREDENTIALS_FILE="$TASK_DIR/credentials.json"
set +e
"$TASK_DIR/orbit-schedule-load" -schedules 32 -requests 8 -workers 1 -capacity 1 \
-start-delay 5s -run-timeout "$TASK_RUN_TIMEOUT" -poll-interval 100ms \
>"$TASK_DIR/report.json" 2>"$TASK_DIR/tool.stderr" &
TASK_LOAD_PID=$!
set -e
while kill -0 "$TASK_LOAD_PID" 2>/dev/null; do
TASK_AT=$(date -u +%Y-%m-%dT%H:%M:%S.000Z)
TASK_ROW=$(query 'SELECT (SELECT COUNT(*) FROM pulse_tasks WHERE state="WAITING"),(SELECT COUNT(*) FROM pulse_tasks WHERE state="LEASED"),(SELECT COUNT(*) FROM pulse_tasks WHERE state="RUNNING"),(SELECT COUNT(*) FROM pulse_tasks WHERE state="SUCCEEDED"),(SELECT COUNT(*) FROM pulse_schedule_occurrences),(SELECT COUNT(*) FROM pulse_schedules WHERE paused=FALSE)' 2>/dev/null || true)
set -- $TASK_ROW
if [ "$#" -eq 6 ]; then
printf '{"at":"%s","waiting":%s,"leased":%s,"running":%s,"succeeded":%s,"occurrences":%s,"unpaused_schedules":%s}\n' "$TASK_AT" "$1" "$2" "$3" "$4" "$5" "$6" >>"$TASK_DIR/curve.jsonl"
fi
sleep 2
done
set +e
wait "$TASK_LOAD_PID"
TASK_LOAD_CODE=$?
set -e
TASK_LOAD_PID=
if [ "$TASK_LOAD_CODE" -ne 1 ]; then
printf 'expected orbit-schedule-load exit 1, got %s\n' "$TASK_LOAD_CODE" >&2
cat "$TASK_DIR/tool.stderr" >&2 || true
exit 1
fi
TASK_FINAL=$(query 'SELECT JSON_OBJECT("foreign_key_count",(SELECT COUNT(*) FROM information_schema.referential_constraints WHERE constraint_schema=DATABASE()),"task_count",(SELECT COUNT(*) FROM pulse_tasks),"succeeded_count",(SELECT COUNT(*) FROM pulse_tasks WHERE state="SUCCEEDED"),"occurrence_count",(SELECT COUNT(*) FROM pulse_schedule_occurrences),"unpaused_schedules",(SELECT COUNT(*) FROM pulse_schedules WHERE paused=FALSE));')
TASK_VERIFY=$(ORBIT_MYSQL_DSN="$TASK_DSN" "$TASK_DIR/orbit-admin" verify)
python3 - "$TASK_DIR/report.json" "$TASK_FINAL" <<'PY'
import json
import sys
with open(sys.argv[1], encoding="utf-8") as f:
report = json.load(f)
database = json.loads(sys.argv[2])
if report["expected_occurrences"] != 256 or report["occurrences"] != 256 or report["fired"] != 256:
raise SystemExit("not all bounded schedule occurrences were persisted")
if report["complete"] or report["errors"].get("RUN_TIMEOUT") != 1 or report["unverified"] <= 0:
raise SystemExit("deadline negative sample did not preserve an incomplete denominator")
if not all(plan["pause_confirmed"] for plan in report["plans"]):
raise SystemExit("not every created schedule was confirmed paused")
if database["task_count"] != 256 or database["occurrence_count"] != 256 or database["unpaused_schedules"] != 0 or database["foreign_key_count"] != 0:
raise SystemExit("final database evidence is inconsistent")
PY
TASK_POINTS=$(wc -l <"$TASK_DIR/curve.jsonl" | tr -d ' ')
if [ "${ORBIT_TEST_KEEP_ARTIFACTS:-0}" = 1 ]; then
mkdir -p "${ORBIT_TEST_KEEP_ARTIFACTS_PATH:-/tmp/orbit-schedule-backlog-last}"
cp "$TASK_DIR/report.json" "${ORBIT_TEST_KEEP_ARTIFACTS_PATH:-/tmp/orbit-schedule-backlog-last}/sample-256-deadline.json"
cp "$TASK_DIR/curve.jsonl" "${ORBIT_TEST_KEEP_ARTIFACTS_PATH:-/tmp/orbit-schedule-backlog-last}/curve.jsonl"
printf '%s\n' "$TASK_FINAL" >"${ORBIT_TEST_KEEP_ARTIFACTS_PATH:-/tmp/orbit-schedule-backlog-last}/database.json"
fi
printf '{"tool_exit":%s,"verify":%s,"database":%s,"curve_points":%s}\n' "$TASK_LOAD_CODE" "$TASK_VERIFY" "$TASK_FINAL" "$TASK_POINTS"