Commit f3100907 authored by 郭阔's avatar 郭阔

fix(harvest/modify-source): correct retry criterion + guard schedule reload during runs

- attempt_needs_retry checked .result type, but the envelope's result is a
  plain text message even on success — the structured business result lives
  in .structured_output. Every healthy run was therefore misjudged and
  silently re-run (attempt2 all_seen fast-exits made it cheap and invisible;
  reuters-technology went to attempt3 and was then killed by a schedule
  reload). Criterion now: rc!=0 / empty / invalid JSON / structured_output
  not an object / is_error.
- modify-source.sh refuses to reload a schedule while the source (site)
  has a live harvest runlock — launchctl bootout terminates the running
  job (exactly what killed reuters-technology attempt3); --force overrides.
  Panel schedule-time route already had this guard; CLI is now covered.
- reuters-technology record rebuilt from its valid attempt1 envelope
  (SUCCESS, 10 articles, matching push syncstate).
parent 5b490bd9
......@@ -147,13 +147,18 @@ ${RESULT_REQUIREMENTS}" \
}
attempt_needs_retry() { # 运行错误/输出无效/API 报错 → 重试;内容质量类失败不触发
# 注意:信封的 .result 字段正常时就是文本消息;结构化结果在 .structured_output。
# 判定成败必须看 structured_output 是否为对象(实测:成功轮 result=str+structured_output=dict;
# GLM 结构化失败轮 structured_output 缺失)。
if [ "$RC" -ne 0 ]; then return 0; fi
if [ ! -s "$JSON_OUT" ]; then return 0; fi
command -v jq >/dev/null 2>&1 || return 1
jq empty "$JSON_OUT" 2>/dev/null || return 0
jq -e '(.result | type) == "object"' "$JSON_OUT" >/dev/null 2>&1 || return 0
if jq -e '(.structured_output | type) == "object"' "$JSON_OUT" >/dev/null 2>&1; then
if jq -e '.is_error == true' "$JSON_OUT" >/dev/null 2>&1; then return 0; fi
return 1
fi
return 0
}
# 失败自动恢复:①失败(运行错误/输出无效/API 错)→ ②同 provider 重试 →
......
......@@ -58,6 +58,7 @@ while [ $# -gt 0 ]; do
--provider) PROVIDER="${2:?--provider 需要值}"; PROVIDER_SET=1; shift 2;;
--fallback-provider) FALLBACK_PROVIDER="${2:?--fallback-provider 需要值}"; FALLBACK_PROVIDER_SET=1; shift 2;;
--yes|-y) ASSUME_NO=1; shift;;
--force) FORCE=1; shift;;
--help|-h) usage; exit 0;;
--) shift; break;;
-*) echo "未知选项: $1" >&2; usage >&2; exit 1;;
......@@ -106,6 +107,19 @@ TIMER_NAME="news-harvester@${SOURCE}.timer"
DROPIN_DIR="$TIMER_PATH.d"
nh_schedule_exists "$SOURCE" || err "调度不存在: $TIMER_PATH\n 可用栏目: $(nh_schedule_list | tr '\n' ' ')"
# --- 采集中保护:重新加载调度(bootout)会终止正在运行的本站采集任务 ---
# 例外:--force(明确要中断重启)。面板 schedule-time 路由已有同样保护,此处兜 CLI。
if [ "${FORCE:-0}" != "1" ]; then
_site_port="$(nh_cdp_port "$(nh_login_site "$SOURCE")")"
for _lk in "$WORK_DIR/runlocks/port-${_site_port}."*.lock; do
[ -e "$_lk" ] || continue
_pid="$(basename "$_lk" .lock)"; _pid="${_pid##*.}"
if [ -n "$_pid" ] && kill -0 "$_pid" 2>/dev/null; then
err "${SOURCE} 正在采集(PID ${_pid}),重新加载调度会终止它。等任务结束再改,或用 --force 明确中断"
fi
done
fi
# --- 读取当前生效时间(统一走平台层:linux 含 drop-in,darwin 读 plist) ---
CURRENT_TIME="$(nh_schedule_read "$SOURCE")"
[ -z "$CURRENT_TIME" ] && CURRENT_TIME="(未知)"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment