Skip to content

Commit cd712e6

Browse files
bugaleCopilot
andcommitted
fix: scheduler busy-spins instead of waiting for test completion
run_tests computed the asyncio.wait timeout as elapsed - task_timeout, which is negative until the deadline, so asyncio.wait returned immediately and the while loop spun at 100% CPU for the entire run. Flip it back to time-remaining (task_timeout - elapsed) and clamp it to at least 1 second so sub-second remainders (truncated to 0 by int()) and already-expired deadlines keep polling instead of spinning. Present since v0.20.0 (d8e08d1). Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
1 parent 580309e commit cd712e6

2 files changed

Lines changed: 26 additions & 2 deletions

File tree

pytest_asyncio_cooperative/plugin.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,11 +200,11 @@ async def run_tests(tasks, max_tasks: int, session, item_by_coro):
200200
item.enqueue_time = time.time()
201201
earliest_enqueue_time = min(item.enqueue_time, earliest_enqueue_time)
202202

203-
time_to_wait = (time.time() - earliest_enqueue_time) - task_timeout
203+
time_to_wait = task_timeout - (time.time() - earliest_enqueue_time)
204204
done, pending = await asyncio.wait(
205205
tasks,
206206
return_when=asyncio.FIRST_COMPLETED,
207-
timeout=min(30, int(time_to_wait)),
207+
timeout=min(30, max(1, int(time_to_wait))),
208208
)
209209

210210
# Cancel tasks that have taken too long

tests/test_bugs.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import time
2+
3+
14
def test_cached_function_can_handle_kwargs(testdir):
25
testdir.makepyfile(
36
"""
@@ -16,3 +19,24 @@ def test_b(pytestconfig):
1619
)
1720
result = testdir.runpytest()
1821
result.assert_outcomes(passed=2)
22+
23+
24+
def test_scheduler_sleeps_while_waiting_for_tests(testdir):
25+
"""The scheduling loop must block in asyncio.wait until a test completes,
26+
not busy-spin with an expired timeout (issue: elapsed/timeout operands were flipped)."""
27+
testdir.makepyfile(
28+
"""
29+
import asyncio
30+
import pytest
31+
32+
33+
@pytest.mark.asyncio_cooperative
34+
async def test_sleep():
35+
await asyncio.sleep(3)
36+
"""
37+
)
38+
start = time.process_time()
39+
result = testdir.runpytest()
40+
cpu_time = time.process_time() - start
41+
result.assert_outcomes(passed=1)
42+
assert cpu_time < 1.5, f"scheduler burned {cpu_time:.1f}s CPU while the only test was sleeping"

0 commit comments

Comments
 (0)