fix: isolate push channel schedules (Closes #713)
CI / lint (pull_request) Successful in 1m27s
CI / build-release (pull_request) Successful in 6s
CI / release-candidate (pull_request) Has been skipped

This commit is contained in:
timmy committed 2026-08-13 06:22:58 +00:00
1 parent 8387c57ceb
commit b069379df0
3 files changed
+110 -17

No files matched your search

+71 -2
View File
@@ -235,11 +235,16 @@ async def test_push_poll_still_dispatches_deadlines_when_unread_dispatch_fails(m
calls = []
sleeps = 0
first_tick = asyncio.Event()
async def no_wait(_seconds):
nonlocal sleeps
sleeps += 1
if sleeps > 1:
if sleeps <= 2:
if sleeps == 2:
first_tick.set()
await first_tick.wait()
else:
raise asyncio.CancelledError
async def fail_unread(*_args, **_kwargs):
@@ -256,7 +261,71 @@ async def test_push_poll_still_dispatches_deadlines_when_unread_dispatch_fails(m
with pytest.raises(asyncio.CancelledError):
await main._push_poll_loop()
assert calls == ["unread", "deadline"]
assert sorted(calls) == ["deadline", "unread"]
@pytest.mark.anyio
async def test_push_poll_deadlines_continue_while_unread_dispatch_is_blocked(monkeypatch):
unread_started = asyncio.Event()
release_unread = asyncio.Event()
deadline_started = asyncio.Event()
async def no_wait(_seconds):
return None
async def blocked_unread(*_args, **_kwargs):
unread_started.set()
await release_unread.wait()
async def dispatch_deadlines(*_args, **_kwargs):
deadline_started.set()
await release_unread.wait()
monkeypatch.setattr(main.asyncio, "sleep", no_wait)
monkeypatch.setattr(main, "dispatch_unread_updates", blocked_unread)
monkeypatch.setattr(main, "dispatch_deadline_reminders", dispatch_deadlines)
poll = asyncio.create_task(main._push_poll_loop())
await asyncio.wait_for(unread_started.wait(), timeout=0.5)
try:
await asyncio.wait_for(deadline_started.wait(), timeout=0.5)
finally:
poll.cancel()
with pytest.raises(asyncio.CancelledError):
await poll
@pytest.mark.anyio
async def test_push_channel_loop_skips_missed_ticks_without_overlapping(monkeypatch):
starts = []
now = 0.0
class Loop:
def time(self):
return now
async def record_dispatch():
nonlocal now
starts.append("dispatch")
now = 16.0 if len(starts) == 1 else now
if len(starts) == 2:
raise asyncio.CancelledError
sleeps = []
async def capture_sleep(seconds):
nonlocal now
sleeps.append(seconds)
now += seconds
monkeypatch.setattr(main.asyncio, "get_running_loop", lambda: Loop())
monkeypatch.setattr(main.asyncio, "sleep", capture_sleep)
with pytest.raises(asyncio.CancelledError):
await main._push_channel_loop(record_dispatch, interval=5.0)
assert starts == ["dispatch", "dispatch"]
assert sleeps == [5.0, 4.0]
def test_dispatch_leases_are_isolated_by_channel(tmp_path):