diff --git a/hooks/queue-drain-guard.sh b/hooks/queue-drain-guard.sh index d79dfcb..6213bb1 100755 --- a/hooks/queue-drain-guard.sh +++ b/hooks/queue-drain-guard.sh @@ -85,12 +85,27 @@ case "$INFO" in *) note "⚪ 略過" "$INFO"; exit 0 ;; esac -# ② 問佇列(同一支 pick、同一套規則) +# ② 問佇列(同一支 pick、同一套規則),**有時限** +# 2026-09-13 本機實量:Gitea 同一分鐘 curl 60s 逾時、urllib 17s/0.3s/42s 握手逾時, +# 整趟 `pick --all` 跑了約 15 分鐘。hooks.json 給本閘 180s;閘被 Claude Code 砍掉=非阻擋錯誤=放行收工, +# 正好又回到「讀不到就停」。⇒ 自己在 150s 收手,逾時當成「讀不到」(擋,叫它重跑 pick)。 if [ -n "${ISEP_DRAIN_PICK_CMD:-}" ]; then - OUT=$(sh -c "$ISEP_DRAIN_PICK_CMD" 2>/dev/null); RC=$? + PICK_ARGV="sh -c \"\$ISEP_DRAIN_PICK_CMD\"" else - OUT=$(python3 "$PLUGIN_ROOT/scripts/ticket" pick --json 2>/dev/null); RC=$? + PICK_ARGV="python3 \"$PLUGIN_ROOT/scripts/ticket\" pick --json" fi +OUT=$(PICK_ARGV="$PICK_ARGV" python3 -c ' +import os, subprocess, sys +try: + lim = float(os.environ.get("ISEP_DRAIN_PICK_TIMEOUT", "150")) +except ValueError: + lim = 150.0 +try: + p = subprocess.run(["sh", "-c", os.environ["PICK_ARGV"]], capture_output=True, text=True, timeout=lim) + sys.stdout.write(p.stdout); sys.exit(p.returncode) +except subprocess.TimeoutExpired: + sys.exit(124) +' 2>/dev/null); RC=$? STATE="$STATE_DIR/.queue-drain-$SID.json" VERDICT=$(OUT="$OUT" RC="$RC" STATE="$STATE" python3 -c ' diff --git a/hooks/tests/queue-drain-guard.test.sh b/hooks/tests/queue-drain-guard.test.sh index e673628..8794aca 100755 --- a/hooks/tests/queue-drain-guard.test.sh +++ b/hooks/tests/queue-drain-guard.test.sh @@ -90,6 +90,10 @@ run "讀不到第 2 次 → 擋" 2 s9 worker.jsonl run "★ 讀不到第 3 次 → 放行並留痕" 0 s9 worker.jsonl check "log 有 unreachable" "grep -q 'unreachable' '$TMP/state-s9/queue-drain-guard.log'" +printf '0' > "$TMP/rc"; printf '%s' "$TICKET" > "$TMP/out" +ISEP_DRAIN_PICK_CMD="sleep 5; sh $TMP/pick.sh" ISEP_DRAIN_PICK_TIMEOUT=1 run "★ pick 超過時限(Gitea 慢)→ 當成讀不到而擋,不是被砍掉後放行" 2 s10 worker.jsonl +check "逾時那次訊息是「讀不到 ≠ 沒票」" "grep -q '讀不到' '$TMP/stderr'" + echo echo "── ④ 真的 pick(不帶假指令)接得上 ──" unset ISEP_DRAIN_PICK_CMD