Skip to content

Commit 9ce48f9

Browse files
authored
fix: raise RuntimeError when AsyncPipeline.run() is called from within an async context (#9712)
* Raise RuntimeError when AsyncPipeline.run() is called from an async context * Add release note
1 parent 8bb8b67 commit 9ce48f9

3 files changed

Lines changed: 41 additions & 3 deletions

File tree

haystack/core/pipeline/async_pipeline.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -676,7 +676,20 @@ def run(
676676
Or if a Component fails or returns output in an unsupported type.
677677
:raises PipelineMaxComponentRuns:
678678
If a Component reaches the maximum number of times it can be run in this Pipeline.
679+
:raises RuntimeError:
680+
If called from within an async context. Use `run_async` instead.
679681
"""
680-
return asyncio.run(
681-
self.run_async(data=data, include_outputs_from=include_outputs_from, concurrency_limit=concurrency_limit)
682-
)
682+
try:
683+
asyncio.get_running_loop()
684+
except RuntimeError:
685+
# No running loop: safe to use asyncio.run()
686+
return asyncio.run(
687+
self.run_async(
688+
data=data, include_outputs_from=include_outputs_from, concurrency_limit=concurrency_limit
689+
)
690+
)
691+
else:
692+
# Running loop present: do not create the coroutine and do not call asyncio.run()
693+
raise RuntimeError(
694+
"Cannot call run() from within an async context. Use 'await pipeline.run_async(...)' instead."
695+
)
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
fixes:
3+
- |
4+
Raise a `RuntimeError` when `AsyncPipeline.run` is called from within an async context, indicating that `run_async` should be used instead.

test/core/pipeline/test_async_pipeline.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
import asyncio
66

7+
import pytest
8+
79
from haystack import AsyncPipeline
810

911

@@ -22,3 +24,22 @@ async def run_all():
2224
component_spans = [sp for sp in spying_tracer.spans if sp.operation_name == "haystack.component.run_async"]
2325
for span in component_spans:
2426
assert span.tags["haystack.component.visits"] == 1
27+
28+
29+
def test_run_in_sync_context(waiting_component):
30+
pp = AsyncPipeline()
31+
pp.add_component("wait", waiting_component())
32+
33+
result = pp.run({"wait_for": 0.001})
34+
35+
assert result == {"wait": {"waited_for": 0.001}}
36+
37+
38+
def test_run_in_async_context_raises_runtime_error():
39+
pp = AsyncPipeline()
40+
41+
async def call_run():
42+
pp.run({})
43+
44+
with pytest.raises(RuntimeError, match="Cannot call run\\(\\) from within an async context"):
45+
asyncio.run(call_run())

0 commit comments

Comments
 (0)