更新
This commit is contained in:
@@ -389,6 +389,10 @@ class GlobalSendQueueTests(unittest.IsolatedAsyncioTestCase):
|
||||
|
||||
|
||||
class BackgroundTrafficLimitTests(unittest.IsolatedAsyncioTestCase):
|
||||
async def _wait_until(self, predicate) -> None:
|
||||
while not predicate():
|
||||
await asyncio.sleep(0.001)
|
||||
|
||||
async def test_background_slot_respects_configured_concurrency_limit(self):
|
||||
with patch.dict(
|
||||
os.environ,
|
||||
@@ -458,6 +462,83 @@ class BackgroundTrafficLimitTests(unittest.IsolatedAsyncioTestCase):
|
||||
self.assertEqual(len(tasks_seen), 3)
|
||||
self.assertTrue(all(task is tasks_seen[0] for task in tasks_seen))
|
||||
|
||||
async def test_startup_traffic_leaves_one_slot_for_recurring_work(self):
|
||||
with patch.dict(
|
||||
os.environ,
|
||||
{"KEFU_BACKGROUND_NETWORK_CONCURRENCY": "3"},
|
||||
):
|
||||
controller = TrafficController()
|
||||
self.addAsyncCleanup(controller.stop)
|
||||
|
||||
entered: list[str] = []
|
||||
release = asyncio.Event()
|
||||
|
||||
async def request(name: str, *, startup: bool = False) -> None:
|
||||
async with controller.background_slot(1, name, startup=startup):
|
||||
entered.append(name)
|
||||
await release.wait()
|
||||
|
||||
starts = [
|
||||
asyncio.create_task(request(f"startup-{index}", startup=True))
|
||||
for index in range(3)
|
||||
]
|
||||
while len(entered) < 2:
|
||||
await asyncio.sleep(0)
|
||||
await asyncio.sleep(0.01)
|
||||
|
||||
# A flood of startups may occupy at most capacity - 1 slots, so a
|
||||
# recurring poll still gets in while the fleet is coming online.
|
||||
self.assertEqual(len(entered), 2)
|
||||
self.assertEqual(controller.background_startup_active, 2)
|
||||
|
||||
poll = asyncio.create_task(request("poll"))
|
||||
await asyncio.wait_for(
|
||||
self._wait_until(lambda: "poll" in entered),
|
||||
timeout=0.5,
|
||||
)
|
||||
|
||||
release.set()
|
||||
await asyncio.wait_for(asyncio.gather(*starts, poll), timeout=0.5)
|
||||
self.assertEqual(controller.background_active, 0)
|
||||
self.assertEqual(controller.background_startup_active, 0)
|
||||
|
||||
async def test_recurring_work_is_not_deferred_indefinitely_by_startups(self):
|
||||
"""Pending startup work may delay a recurring poll, never block it.
|
||||
|
||||
Starting several hundred accounts keeps startup requests queued for the
|
||||
whole run. Yielding to that queue without a deadline left every hosted
|
||||
account silent until the last account had finished coming online.
|
||||
"""
|
||||
with patch.dict(
|
||||
os.environ,
|
||||
{
|
||||
"KEFU_BACKGROUND_NETWORK_CONCURRENCY": "1",
|
||||
"KEFU_BACKGROUND_NORMAL_MAX_DEFER_SECONDS": "0.02",
|
||||
},
|
||||
):
|
||||
controller = TrafficController()
|
||||
self.addAsyncCleanup(controller.stop)
|
||||
|
||||
entered: list[str] = []
|
||||
release = asyncio.Event()
|
||||
|
||||
async def poll() -> None:
|
||||
async with controller.background_slot(1, "conversation poll"):
|
||||
entered.append("poll")
|
||||
await release.wait()
|
||||
|
||||
# Stands in for a batch whose startup requests never stop arriving.
|
||||
controller._background_startup_clear.clear()
|
||||
|
||||
task = asyncio.create_task(poll())
|
||||
await asyncio.wait_for(
|
||||
self._wait_until(lambda: entered == ["poll"]),
|
||||
timeout=1.0,
|
||||
)
|
||||
|
||||
release.set()
|
||||
await asyncio.wait_for(task, timeout=0.5)
|
||||
|
||||
async def test_startup_request_is_not_buried_behind_normal_backlog(self):
|
||||
with patch.dict(
|
||||
os.environ,
|
||||
|
||||
Reference in New Issue
Block a user