fix: pace failed calendar refresh retries
ci / gitleaks (push) Successful in 7s
ci / docker (push) Successful in 3m11s

This commit is contained in:
2026-09-21 15:38:52 +08:00
parent 97c1bd4e87
commit a68d6ecc5e
2 changed files with 66 additions and 5 deletions
+55
View File
@@ -351,3 +351,58 @@ def test_refresh_discards_response_when_url_changes_in_flight(monkeypatch):
assert row.url == "https://example.com/new.ics"
assert row.ics_cache is None
assert db.committed is False
def test_failed_source_waits_until_next_interval_and_does_not_abort_batch(client, monkeypatch):
client = initialized(client)
monkeypatch.setattr(
"backend.calendar.validate_calendar_url",
lambda url: (url, "93.184.216.34", 443),
)
monkeypatch.setattr(
"backend.calendar.fetch_calendar",
lambda *args, **kwargs: FetchResult(ICS, None, None, False),
)
first = client.post(
"/api/v1/calendar-subscriptions",
json={"name": "first", "url": "https://example.com/first.ics"},
).json()
client.post(
"/api/v1/calendar-subscriptions",
json={"name": "second", "url": "https://example.com/second.ics"},
)
attempts = []
def fetch(url, **kwargs):
attempts.append(url)
if url.endswith("first.ics"):
raise HTTPException(502, "upstream down")
return FetchResult(ICS, None, None, False)
monkeypatch.setattr("backend.calendar.fetch_calendar", fetch)
async def refresh_twice():
from sqlalchemy.ext.asyncio import async_sessionmaker
from backend.db import get_engine
factory = async_sessionmaker(get_engine(), expire_on_commit=False)
now = datetime.now(UTC) + timedelta(minutes=16)
async with factory() as db:
first_count = await refresh_due_subscriptions(
db, now=now, refresh_interval=timedelta(minutes=15)
)
async with factory() as db:
second_count = await refresh_due_subscriptions(
db, now=now + timedelta(minutes=1), refresh_interval=timedelta(minutes=15)
)
return first_count, second_count
assert asyncio.run(refresh_twice()) == (2, 0)
assert attempts == [
"https://example.com/first.ics",
"https://example.com/second.ics",
]
listed = client.get("/api/v1/calendar-subscriptions").json()
failed = next(item for item in listed if item["id"] == first["id"])
assert failed["stale"] is True