Hermes scheduler .tick.lock + hermes cron status 수정 보고
발견
- 증상 1:
18789포트는 LISTEN인데hermes cron status가 게이트웨이 미실행으로 판단했다. - 증상 2:
.tick.lock을 Hermes gateway 프로세스가 오래 잡아 두 번째 tick/cycle이lock_busy로 건너뛰었다. - 확인 증거:
- 기존 PID
45753가/Users/ron/.hermes/cron/.tick.lock을 잡고 있었음. - 기존 로그에 장시간 LLM/tool 작업 중 gateway가 계속 진행 중인 흔적이 있었음.
scheduler_state.json에status=skipped_lock_busy,last_tick_error=lock_busy가 기록됨.
원인
1) tick lock
cron/scheduler.py의 기존tick()은fcntllock을 잡은 상태에서run_job(job)까지 실행했다.try/finally자체는 있었으므로 “락 해제 누락”이라기보다 락 범위가 너무 넓은 설계였다.- LLM/tool 호출이 오래 걸리면, scheduler 예약용 lock이 실제 작업 실행 시간 전체를 막아 다음 tick이 진행되지 않았다.
- 기존에는 5분 이상 점유 같은 stale timeout/자동 해제 정책이 없었다.
2) cron status
hermes_cli/cron.py는find_gateway_pids()기반으로만 gateway 실행 여부를 판정했다.- 실제 gateway는
127.0.0.1:18789에서 LISTEN 중이었지만, 프로세스명 패턴 탐지에 걸리지 않아 “gateway not running”으로 오판했다.
수정
백업 파일:
/Users/ron/.hermes/hermes-agent/cron/scheduler.py.bak-lockfix-20260414143005/Users/ron/.hermes/hermes-agent/hermes_cli/cron.py.bak-statusfix-20260414143005/Users/ron/.hermes/hermes-agent/hermes_cli/gateway.py.bak-statusfix-20260414143005
수정 파일:
/Users/ron/.hermes/hermes-agent/cron/scheduler.py66-73: lock/state 파일 상수와 기본 timeout 추가HERMES_CRON_LOCK_STALE_SECONDS=300기본값HERMES_CRON_SCHEDULER_STALE_SECONDS=180기본값
76-166: lock metadata 기록, lock age 측정, stale lock break, unlock helper 추가176-246: scheduler health 상태 파일(scheduler_state.json) 저장/조회 추가-
944-1049:tick()구조 변경- lock은 due job 예약(
advance_next_run) 동안만 유지 - 실제
run_job()은 lock 해제 후 실행 - 모든 경로에서 scheduler state 기록
- lock은 due job 예약(
-
/Users/ron/.hermes/hermes-agent/hermes_cli/gateway.py 34-58:socket.create_connection()기반 포트 health 확인 추가- socket이 sandbox/권한 문제로 실패하는 경우
lsof -iTCP:18789 -sTCP:LISTENfallback -
63-115: runtime status + HTTP health + scheduler health를 합친gateway_runtime_status()추가 -
/Users/ron/.hermes/hermes-agent/hermes_cli/cron.py 95-101:cron list경고를 새 runtime status 기반으로 변경110-135:cron status를 PID 패턴 단독 판단에서 HTTP API + scheduler health 기반으로 변경
금지 범위 확인:
shared/llm.py수정 없음.~/.openclaw/*수정 없음.
검증
구문 검증
cd /Users/ron/.hermes/hermes-agent
/Users/ron/.hermes/hermes-agent/venv/bin/python -m py_compile cron/scheduler.py hermes_cli/cron.py hermes_cli/gateway.py
결과: py_compile_ok
stale lock 자동 해제 검증
테스트 방식:
- 별도 프로세스가
.tick.lock을 잡도록 만들고, HERMES_CRON_LOCK_STALE_SECONDS=1로 낮춰tick()실행.
결과:
WARNING:Breaking stale cron tick lock: /Users/ron/.hermes/cron/.tick.lock age=2.2s threshold=1s
INFO:14:32:28 - No jobs due
executed 0 elapsed 0.01
의미:
- stale lock이 timeout 이후 자동으로 끊겼다.
- 새 tick은 lock 때문에 장시간 멈추지 않았다.
live gateway/status 검증
최종 확인 시각: 2026-04-14 14:38:31 KST.
/Users/ron/.local/bin/hermes cron status
결과:
✓ Gateway is running — cron jobs will fire automatically
HTTP API: 127.0.0.1:18789 healthy
Scheduler: tick healthy
7 active job(s)
Next run: 2026-04-14T22:10:00+09:00
LISTEN 확인:
Python 63520 ron ... TCP 127.0.0.1:18789 (LISTEN)
lock holder 최종 확인:
lsof /Users/ron/.hermes/cron/.tick.lock
결과: 출력 없음 — 현재 lock을 오래 잡고 있는 프로세스 없음.
scheduler state 최종 확인:
{
"status": "ok",
"last_tick_error": null,
"last_tick_executed": 0,
"last_tick_reserved": 0,
"pid": 63520
}
참고:
hermes gateway start는 launchctl 권한/입출력 오류로 실패했다. 이후hermes gateway run을 백그라운드로 수동 실행해 patched gateway를 PID63520으로 띄웠고,18789LISTEN +cron status정상으로 재확인했다. (nice(5) failed경고는 sandbox 권한 경고이며 gateway 실행에는 영향 없음.)
현재 상태
.tick.lock장시간 점유 문제는 코드상 두 겹으로 방어됨.- lock 범위 축소: job 실행 전 lock 해제
- stale timeout: 기본 300초 이상 점유 lock 자동 break
hermes cron status는 더 이상 프로세스명 스캔만 믿지 않고, HTTP API 포트 + runtime status + scheduler health로 판정한다.- 최종
hermes cron status는 정상 응답.
잔존 리스크
- 실행 중인 gateway 프로세스가 오래된 코드를 물고 있으면 패치가 즉시 반영되지 않는다. 이번에는 최종 PID
63520이 새 gateway 코드로18789LISTEN 상태이며,cron status가 patched health 경로로 정상 확인됐다. - direct socket connect가 제한된 shell에서 실패할 수 있어
lsoffallback을 넣었다. 이 fallback은 로컬 CLI health 표시용이다. - stale lock break는 lock file inode를 교체한다. 기존 holder가 매우 늦게 종료되면 자기 fd만 unlock하므로 새 lock에는 영향이 없게 설계했지만, 동일 job 중복 실행 방지는
advance_next_run()예약 순서에 의존한다.
자체 평가
- 정확성: 4.8/5 — 원인 확인 후 lock 범위/timeout/status 판정 모두 수정했고 live status 정상 확인.
- 완성도: 4.7/5 — 코드 패치, 백업, 구문검사, live 검증 완료.
- 검증: 4.7/5 — py_compile, stale lock simulation, LISTEN, status, lock holder 확인 완료.
- 최소 변경: 4.5/5 — Hermes 범위에만 수정. scheduler health state 추가로 변경량은 다소 있지만 status 신뢰성 확보에 필요.
종합: 4.7/5
최종 재확인 추가 로그
2026-04-14 14:38:31 KST 기준:
Python 63520 ron ... TCP 127.0.0.1:18789 (LISTEN)
✓ Gateway is running — cron jobs will fire automatically
HTTP API: 127.0.0.1:18789 healthy
Scheduler: tick healthy
7 active job(s)
Next run: 2026-04-14T22:10:00+09:00
.tick.lock holder: 없음.