Skip to content

Commit 3aae7f6

Browse files
Merge pull request #2536 from gitautoai/wes
Fix Python 3.14 asyncio event loop crash in Mangum webhook handler
2 parents ab90be5 + 6e36231 commit 3aae7f6

4 files changed

Lines changed: 34 additions & 2 deletions

File tree

main.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# Standard imports
2+
import asyncio
23
import json
34
from typing import Any, cast
45
import urllib.parse
@@ -108,6 +109,13 @@ def handler(event, context):
108109
)
109110
return None
110111

112+
# Python 3.14 removed implicit event loop creation in asyncio.get_event_loop(), which Mangum's HTTPCycle.__call__ still uses. Ensure one exists before each request.
113+
try:
114+
asyncio.get_event_loop()
115+
except RuntimeError:
116+
logger.info("No event loop found, creating one for Mangum")
117+
asyncio.set_event_loop(asyncio.new_event_loop())
118+
111119
# mangum_handler converts requests from API Gateway to FastAPI routing system
112120
return mangum_handler(event=event, context=context)
113121

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "GitAuto"
3-
version = "1.1.7"
3+
version = "1.1.9"
44
requires-python = ">=3.14"
55
dependencies = [
66
"annotated-doc==0.0.4",

test_main.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -819,6 +819,30 @@ async def test_handle_webhook_logs_json_parsing_error(
819819
assert str(call_args[0][1]) == "JSON parsing error"
820820

821821

822+
class TestEventLoopSetup:
823+
@patch("main.mangum_handler")
824+
def test_handler_creates_event_loop_when_missing(self, mock_mangum_handler):
825+
"""Python 3.14 removed implicit event loop creation in asyncio.get_event_loop().
826+
Verify handler creates one before calling mangum_handler."""
827+
event = {"key": "value"}
828+
context = {"context": "data"}
829+
mock_mangum_handler.return_value = {"status": "success"}
830+
831+
# Remove the current event loop to simulate Python 3.14 behavior
832+
policy = asyncio.get_event_loop_policy()
833+
policy.set_event_loop(None) # type: ignore[arg-type]
834+
835+
# handler() should NOT raise RuntimeError — it ensures a loop exists
836+
result = handler(event=event, context=context)
837+
838+
mock_mangum_handler.assert_called_with(event=event, context=context)
839+
assert result == {"status": "success"}
840+
841+
# Verify an event loop now exists
842+
loop = asyncio.get_event_loop()
843+
assert loop is not None
844+
845+
822846
class TestModuleImports:
823847
def test_required_imports_available(self):
824848
"""Test that all required modules and functions are properly imported."""

uv.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)