fix: wrap breaker calls in stage_loop to prevent permanent task death
Some checks are pending
CI / lint-and-test (push) Waiting to run
Some checks are pending
CI / lint-and-test (push) Waiting to run
A transient DB lock in breaker.record_failure() inside an except handler killed the asyncio coroutine permanently — snapshot_cycle died Apr 18 and never recovered. All three breaker call sites now have their own try/except. Also includes HTML injection fix for github_feedback review_text. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
83526bc90e
commit
cde92d3db1
2 changed files with 16 additions and 5 deletions
|
|
@ -125,7 +125,8 @@ async def on_eval_complete(conn, forgejo_pr: int, *, outcome: str, review_text:
|
||||||
if outcome == "approved":
|
if outcome == "approved":
|
||||||
body = "**Evaluation: Approved**\n\nYour contribution passed automated review and is queued for merge."
|
body = "**Evaluation: Approved**\n\nYour contribution passed automated review and is queued for merge."
|
||||||
if review_text:
|
if review_text:
|
||||||
body += f"\n\n<details>\n<summary>Review details</summary>\n\n{review_text[:3000]}\n\n</details>"
|
safe_text = review_text[:3000].replace("</details>", "</details>")
|
||||||
|
body += f"\n\n<details>\n<summary>Review details</summary>\n\n{safe_text}\n\n</details>"
|
||||||
elif outcome == "rejected":
|
elif outcome == "rejected":
|
||||||
body = "**Evaluation: Changes Requested**\n\n"
|
body = "**Evaluation: Changes Requested**\n\n"
|
||||||
if issues:
|
if issues:
|
||||||
|
|
@ -133,7 +134,8 @@ async def on_eval_complete(conn, forgejo_pr: int, *, outcome: str, review_text:
|
||||||
for issue in issues:
|
for issue in issues:
|
||||||
body += f"- {issue}\n"
|
body += f"- {issue}\n"
|
||||||
if review_text:
|
if review_text:
|
||||||
body += f"\n<details>\n<summary>Full review</summary>\n\n{review_text[:3000]}\n\n</details>"
|
safe_text = review_text[:3000].replace("</details>", "</details>")
|
||||||
|
body += f"\n<details>\n<summary>Full review</summary>\n\n{safe_text}\n\n</details>"
|
||||||
body += (
|
body += (
|
||||||
"\n\nThe pipeline will attempt automated fixes where possible. "
|
"\n\nThe pipeline will attempt automated fixes where possible. "
|
||||||
"If fixes fail, the PR will be closed — you're welcome to resubmit."
|
"If fixes fail, the PR will be closed — you're welcome to resubmit."
|
||||||
|
|
|
||||||
|
|
@ -47,12 +47,21 @@ async def stage_loop(name: str, interval: int, func, conn, breaker: CircuitBreak
|
||||||
workers = breaker.max_workers()
|
workers = breaker.max_workers()
|
||||||
succeeded, failed = await func(conn, max_workers=workers)
|
succeeded, failed = await func(conn, max_workers=workers)
|
||||||
if failed > 0 and succeeded == 0:
|
if failed > 0 and succeeded == 0:
|
||||||
breaker.record_failure()
|
try:
|
||||||
|
breaker.record_failure()
|
||||||
|
except Exception:
|
||||||
|
logger.warning("Stage %s: breaker write failed", name)
|
||||||
elif succeeded > 0:
|
elif succeeded > 0:
|
||||||
breaker.record_success()
|
try:
|
||||||
|
breaker.record_success()
|
||||||
|
except Exception:
|
||||||
|
logger.warning("Stage %s: breaker write failed", name)
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.exception("Stage %s: unhandled error in cycle", name)
|
logger.exception("Stage %s: unhandled error in cycle", name)
|
||||||
breaker.record_failure()
|
try:
|
||||||
|
breaker.record_failure()
|
||||||
|
except Exception:
|
||||||
|
logger.warning("Stage %s: breaker write failed", name)
|
||||||
|
|
||||||
# Wait for interval or shutdown, whichever comes first
|
# Wait for interval or shutdown, whichever comes first
|
||||||
try:
|
try:
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue