fix(history): back off retryable source failures
This commit is contained in:
parent
5f21e685ef
commit
575e7aaffd
3 changed files with 31 additions and 0 deletions
|
|
@ -10,6 +10,7 @@
|
|||
"notion_batch_size": 600,
|
||||
"git_batch_size": 500,
|
||||
"review_queue_backfill_batch_size": 500,
|
||||
"source_retry_backoff_seconds": 1800,
|
||||
"semantic_review_endpoint": "http://127.0.0.1:8077/v1/broadcast",
|
||||
"semantic_review_interval_seconds": 600,
|
||||
"semantic_review_batch_size": 8,
|
||||
|
|
|
|||
|
|
@ -81,6 +81,20 @@ def blocks_later_history(status: str) -> bool:
|
|||
return status != "COMPLETE" and status not in SOURCE_WAITING_STATUSES
|
||||
|
||||
|
||||
def retry_backoff_elapsed(
|
||||
updated_at: str | None, backoff_seconds: int, now_unix: float | None = None
|
||||
) -> bool:
|
||||
"""Keep retryable sources alive without writing one failure per runtime cycle."""
|
||||
if not updated_at:
|
||||
return True
|
||||
try:
|
||||
last_attempt = datetime.fromisoformat(updated_at).timestamp()
|
||||
except (TypeError, ValueError):
|
||||
return True
|
||||
current = time.time() if now_unix is None else now_unix
|
||||
return current - last_attempt >= backoff_seconds
|
||||
|
||||
|
||||
def redact_semantic_excerpt(text: str) -> str:
|
||||
text = re.sub(
|
||||
r"\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b",
|
||||
|
|
@ -1016,6 +1030,12 @@ class Runtime:
|
|||
)
|
||||
|
||||
def process_source(self, source: dict) -> None:
|
||||
state = self.store.state(source["id"])
|
||||
if state["status"] == "ERROR_RETRYABLE" and not retry_backoff_elapsed(
|
||||
state["updated_at"],
|
||||
int(self.config.get("source_retry_backoff_seconds", 1800)),
|
||||
):
|
||||
return
|
||||
try:
|
||||
if source["kind"] == "gpt_export":
|
||||
self.process_gpt(source)
|
||||
|
|
|
|||
|
|
@ -47,6 +47,16 @@ class RuntimeTests(unittest.TestCase):
|
|||
self.assertFalse(runtime.blocks_later_history("COMPLETE"))
|
||||
self.assertFalse(runtime.blocks_later_history("WAITING_FOR_SOURCE_ACCEPTANCE"))
|
||||
|
||||
def test_retryable_source_uses_bounded_backoff(self):
|
||||
updated_at = "1970-01-01T00:00:00+00:00"
|
||||
self.assertFalse(
|
||||
runtime.retry_backoff_elapsed(updated_at, 1800, now_unix=1799)
|
||||
)
|
||||
self.assertTrue(
|
||||
runtime.retry_backoff_elapsed(updated_at, 1800, now_unix=1800)
|
||||
)
|
||||
self.assertTrue(runtime.retry_backoff_elapsed("invalid", 1800))
|
||||
|
||||
def test_semantic_redaction_and_reality_boundary(self):
|
||||
redacted = runtime.redact_semantic_excerpt(
|
||||
"a@example.com token: sk-abcdefghijklmnop "
|
||||
|
|
|
|||
Loading…
Reference in a new issue