Skip to content

Commit d99ba3b

Browse files
authored
fix: do not use get_event_loop in GunicornWebWorker - 3.13 (#12057)
1 parent 9d8dcec commit d99ba3b

File tree

3 files changed

+31
-4
lines changed

3 files changed

+31
-4
lines changed

CHANGES/11701.bugfix.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fixed ``RuntimeError: An event loop is running`` error when using ``aiohttp.GunicornWebWorker``
2+
or ``aiohttp.GunicornUVLoopWebWorker`` on Python >=3.14.
3+
-- by :user:`Tasssadar`.

aiohttp/worker.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@
3636

3737

3838
class GunicornWebWorker(base.Worker): # type: ignore[misc,no-any-unimported]
39-
4039
DEFAULT_AIOHTTP_LOG_FORMAT = AccessLogger.LOG_FORMAT
4140
DEFAULT_GUNICORN_LOG_FORMAT = GunicornAccessLogFormat.default
4241

@@ -49,7 +48,11 @@ def __init__(self, *args: Any, **kw: Any) -> None: # pragma: no cover
4948

5049
def init_process(self) -> None:
5150
# create new event_loop after fork
52-
asyncio.get_event_loop().close()
51+
try:
52+
asyncio.get_event_loop().close()
53+
except RuntimeError:
54+
# No loop was running
55+
pass
5356

5457
self.loop = asyncio.new_event_loop()
5558
asyncio.set_event_loop(self.loop)
@@ -245,7 +248,11 @@ def init_process(self) -> None:
245248

246249
# Close any existing event loop before setting a
247250
# new policy.
248-
asyncio.get_event_loop().close()
251+
try:
252+
asyncio.get_event_loop().close()
253+
except RuntimeError:
254+
# No loop was running
255+
pass
249256

250257
# Setup uvloop policy, so that every
251258
# asyncio.get_event_loop() will create an instance

tests/test_worker.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ class AsyncioWorker(BaseTestWorker, base_worker.GunicornWebWorker): # type: ign
4646
if uvloop is not None:
4747

4848
class UvloopWorker(
49-
BaseTestWorker, base_worker.GunicornUVLoopWebWorker # type: ignore
49+
BaseTestWorker,
50+
base_worker.GunicornUVLoopWebWorker, # type: ignore
5051
):
5152
pass
5253

@@ -75,6 +76,22 @@ def test_init_process(worker: base_worker.GunicornWebWorker) -> None:
7576
assert m_asyncio.set_event_loop.called
7677

7778

79+
def test_init_process_no_loop(worker: base_worker.GunicornWebWorker) -> None:
80+
with mock.patch("aiohttp.worker.asyncio") as m_asyncio:
81+
m_asyncio.get_event_loop.side_effect = RuntimeError(
82+
"There is no current event loop in thread 'MainThread'"
83+
)
84+
try:
85+
worker.init_process()
86+
except TypeError:
87+
pass
88+
89+
assert m_asyncio.get_event_loop.called
90+
assert not m_asyncio.get_event_loop.return_value.close.called
91+
assert m_asyncio.new_event_loop.called
92+
assert m_asyncio.set_event_loop.called
93+
94+
7895
def test_run(
7996
worker: base_worker.GunicornWebWorker, loop: asyncio.AbstractEventLoop
8097
) -> None:

0 commit comments

Comments
 (0)