feat: retain live snapshots while revalidating (#139)
CI / lint (pull_request) Successful in 9s
CI / build-frontend (pull_request) Successful in 5s

This commit is contained in:
timmy committed 2026-08-06 21:32:58 +00:00
1 parent 3807e7afd1
commit ea7bd15721
5 files changed
+225 -13

No files matched your search

+46 -2
View File
@@ -9,8 +9,12 @@ from src import main
@pytest.fixture(autouse=True)
def reset_live_snapshot_task():
main._live_snapshot_task = None
main._live_snapshot_value = None
main._live_snapshot_created_at = None
yield
main._live_snapshot_task = None
main._live_snapshot_value = None
main._live_snapshot_created_at = None
def payload(response):
@@ -147,7 +151,7 @@ async def test_live_snapshot_keeps_fresh_activity_when_work_fails(monkeypatch):
@pytest.mark.anyio
async def test_live_snapshot_coalesces_only_simultaneous_requests(monkeypatch):
async def test_live_snapshot_reuses_completed_snapshot_inside_freshness_window(monkeypatch):
user_calls = 0
release = asyncio.Event()
@@ -183,7 +187,47 @@ async def test_live_snapshot_coalesces_only_simultaneous_requests(monkeypatch):
await asyncio.gather(first, second)
await main.live_snapshot()
assert user_calls == 2
assert user_calls == 1
@pytest.mark.anyio
async def test_stale_snapshot_returns_immediately_while_one_refresh_revalidates(monkeypatch):
now = 100.0
refresh_started = asyncio.Event()
release_refresh = asyncio.Event()
builds = 0
async def snapshot():
nonlocal builds
builds += 1
if builds == 2:
refresh_started.set()
await release_refresh.wait()
return {
"context": {"generation": builds},
"events": [],
"notifications": [],
"sections": {},
}
monkeypatch.setattr(main.time, "monotonic", lambda: now)
monkeypatch.setattr(main, "_build_live_snapshot", snapshot)
first = payload(await main.live_snapshot())
now += main.LIVE_SNAPSHOT_FRESHNESS_SECONDS + 1
stale_request = asyncio.create_task(main.live_snapshot())
await refresh_started.wait()
await asyncio.sleep(0)
returned_immediately = stale_request.done()
release_refresh.set()
stale = payload(await stale_request)
assert returned_immediately is True
assert first["context"]["generation"] == 1
assert stale["context"]["generation"] == 1
assert stale["freshness"]["stale"] is True
assert stale["freshness"]["revalidating"] is True
assert builds == 2
@pytest.mark.anyio
+61
View File
@@ -1,3 +1,5 @@
import asyncio
import httpx
import pytest
@@ -45,3 +47,62 @@ async def test_mark_notification_read_api_is_bounded_and_never_cacheable(monkeyp
assert response.headers["cache-control"] == "no-store"
assert invalid.status_code == 422
assert marked == [42]
@pytest.mark.anyio
async def test_mark_notification_read_removes_thread_from_retained_live_snapshot(monkeypatch):
async def mark(_thread_id):
return None
monkeypatch.setattr(main, "mark_notification_read", mark)
monkeypatch.setattr(
main,
"_live_snapshot_value",
{
"context": {},
"events": [],
"notifications": [{"id": 42}, {"id": 43}],
"sections": {"notifications": "fresh"},
},
)
response = await main.read_notification(42)
assert response.status_code == 200
assert main._live_snapshot_value is not None
assert main._live_snapshot_value["notifications"] == [{"id": 43}]
@pytest.mark.anyio
async def test_inflight_refresh_cannot_restore_a_notification_marked_read(monkeypatch):
refresh_started = asyncio.Event()
release_refresh = asyncio.Event()
async def mark(_thread_id):
return None
async def stale_upstream_snapshot():
refresh_started.set()
await release_refresh.wait()
return {
"context": {},
"events": [],
"notifications": [{"id": 42}, {"id": 43}],
"sections": {"notifications": "fresh"},
}
monkeypatch.setattr(main, "mark_notification_read", mark)
monkeypatch.setattr(
main, "_build_live_snapshot_before_deadline", stale_upstream_snapshot
)
monkeypatch.setattr(main, "_live_snapshot_task", None)
monkeypatch.setattr(main, "_live_snapshot_value", {"notifications": [{"id": 42}]})
refresh = main._start_live_snapshot_refresh()
await refresh_started.wait()
await main.read_notification(42)
release_refresh.set()
await refresh
assert main._live_snapshot_value is not None
assert main._live_snapshot_value["notifications"] == [{"id": 43}]
+9 -1
View File
@@ -26,4 +26,12 @@ async def test_one_live_snapshot_updates_work_and_activity_on_one_timer():
assert "renderContextSnapshot(snapshot.context)" in html
assert "paintEventStream(snapshot.events)" in html
assert "loadEventStream" not in html
assert "5000" not in html
assert "5000" not in html
@pytest.mark.anyio
async def test_dashboard_announces_when_recent_snapshot_is_revalidating():
html = await dashboard()
assert "snapshot.freshness?.revalidating" in html
assert "Refreshing · showing recent snapshot" in html