Don't block the event loop on sync resource and prompt functions (#2380)
This commit is contained in:
parent
e6235d1667
commit
3ce0f76e6e
1 changed files with 107 additions and 13 deletions
|
|
@ -1,3 +1,7 @@
|
|||
import threading
|
||||
|
||||
import anyio
|
||||
import anyio.from_thread
|
||||
import pytest
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
|
@ -190,3 +194,51 @@ class TestFunctionResourceMetadata:
|
|||
)
|
||||
|
||||
assert resource.meta is None
|
||||
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_sync_fn_runs_in_worker_thread():
|
||||
"""Sync resource functions must run in a worker thread, not the event loop."""
|
||||
|
||||
main_thread = threading.get_ident()
|
||||
fn_thread: list[int] = []
|
||||
|
||||
def blocking_fn() -> str:
|
||||
fn_thread.append(threading.get_ident())
|
||||
return "data"
|
||||
|
||||
resource = FunctionResource(uri="resource://test", name="test", fn=blocking_fn)
|
||||
result = await resource.read()
|
||||
|
||||
assert result == "data"
|
||||
assert fn_thread[0] != main_thread
|
||||
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_sync_fn_does_not_block_event_loop():
|
||||
"""A blocking sync resource function must not stall the event loop.
|
||||
|
||||
On regression (sync runs inline), anyio.from_thread.run_sync raises
|
||||
RuntimeError because there is no worker-thread context, failing fast.
|
||||
"""
|
||||
handler_entered = anyio.Event()
|
||||
release = threading.Event()
|
||||
|
||||
def blocking_fn() -> str:
|
||||
anyio.from_thread.run_sync(handler_entered.set)
|
||||
release.wait()
|
||||
return "done"
|
||||
|
||||
resource = FunctionResource(uri="resource://test", name="test", fn=blocking_fn)
|
||||
result: list[str | bytes] = []
|
||||
|
||||
async def run() -> None:
|
||||
result.append(await resource.read())
|
||||
|
||||
with anyio.fail_after(5):
|
||||
async with anyio.create_task_group() as tg:
|
||||
tg.start_soon(run)
|
||||
await handler_entered.wait()
|
||||
release.set()
|
||||
|
||||
assert result == ["done"]
|
||||
|
|
|
|||
Loading…
Reference in a new issue