Continuously refill news research slots and report active event waits
Development CI / check-and-build (push) Failing after 2m28s
Development CI / deploy-development (push) Skipped
GitHub Git mirror / mirror (push) Successful in 6s

This commit is contained in:
eezd committed 2026-11-06 15:33:00 +08:00
1 parent 5f347f8ab4
commit 5b733cb1f2
15 files changed
+602 -657

No files matched your search

@@ -948,3 +948,78 @@ def test_enable_cannot_apply_an_unsaved_backfill_time(trading):
assert error.value.status_code == 422
session.scalar.assert_not_awaited()
session.commit.assert_not_awaited()
def test_worker_refills_on_completion_without_waiting_for_other_tasks(trading, monkeypatch):
"""A slow peer must not turn the shared pool back into a batch barrier."""
import asyncio
from unittest.mock import AsyncMock
from alphapulse.news_research import worker
async def scenario():
settings = N(enabled=True, config={'concurrency': 8}, control_revision=1)
class Session:
async def __aenter__(self):
return self
async def __aexit__(self, *args):
pass
async def get(self, *args):
return settings
async def commit(self):
pass
class Lock(Session):
async def scalar(self, *args):
return True
release = asyncio.Event()
first_done = asyncio.Event()
initial_full = asyncio.Event()
refilled = asyncio.Event()
entered = []
live = 0
peak = 0
next_id = 0
async def actions(session, settings, active, slots):
nonlocal next_id
result = [('index', i) for i in range(next_id, next_id + slots)]
next_id += slots
return result
async def process(identifier, config):
nonlocal live, peak
live += 1
peak = max(peak, live)
entered.append(identifier)
if len(entered) == 8:
initial_full.set()
if len(entered) > 8:
refilled.set()
try:
await (first_done.wait() if identifier == 0 else release.wait())
finally:
live -= 1
monkeypatch.setattr(worker, 'engine', N(connect=Lock))
monkeypatch.setattr(worker, 'SessionLocal', Session)
monkeypatch.setattr(worker, 'recover_interrupted', AsyncMock())
monkeypatch.setattr(worker.scheduling, 'actions', actions)
monkeypatch.setattr(worker, 'process_package', process)
task = asyncio.create_task(worker.run())
try:
await asyncio.wait_for(initial_full.wait(), 2)
first_done.set()
await asyncio.wait_for(refilled.wait(), 2)
assert peak == 8 and live == 8 and not release.is_set()
assert len(entered) == 9
finally:
task.cancel()
release.set()
await asyncio.gather(task, return_exceptions=True)
asyncio.run(scenario())