Skip to content

Commit 805d7c2

Browse files
committed
[v3-0-test] Handle trigger calls to get_connection apache#55799
In 2.x sometimes get_connection (which goes to the database) might be called without wrapping in sync_to_async. This did not fail, though it was not good behavior, since it can block the event loop. In 3.0, since we now route db calls through an API, triggers that do this fail. The reason is, the code to hit the API wraps the get_connection call with async_to_sync, which is forbidden in the asyncio event loop. Related: apache#55568 (cherry picked from commit f5b1eb4)
1 parent 8a1b512 commit 805d7c2

2 files changed

Lines changed: 28 additions & 1 deletion

File tree

airflow-core/pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ dependencies = [
153153
"async" = [
154154
"eventlet>=0.37.0",
155155
"gevent>=24.2.1",
156+
"greenback>=1.2.1",
156157
"greenlet>=0.4.9",
157158
]
158159
"graphviz" = [

airflow-core/src/airflow/jobs/triggerer_job_runner.py

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -737,7 +737,24 @@ def _read_frame(self):
737737
def send(self, msg: ToTriggerSupervisor) -> ToTriggerRunner | None:
738738
from asgiref.sync import async_to_sync
739739

740-
return async_to_sync(self.asend)(msg)
740+
try:
741+
return async_to_sync(self.asend)(msg)
742+
except RuntimeError as e:
743+
if str(e).startswith("You cannot use AsyncToSync in the same thread as an async event loop"):
744+
log.warning(
745+
"`TriggerCommsDecoder.send` is being called from within a coroutine without "
746+
"having been wrapped with sync_to_async; attempting to invoke with greenback. "
747+
"You must find where this in being invoked and wrap with sync_to_async."
748+
)
749+
try:
750+
import greenback
751+
752+
task = asyncio.current_task()
753+
if greenback.has_portal(task):
754+
return greenback.await_(self.asend(msg))
755+
except ImportError:
756+
log.warning("greenback unavailable; raising")
757+
raise
741758

742759
async def _aread_frame(self):
743760
len_bytes = await self._async_reader.readexactly(4)
@@ -1064,6 +1081,15 @@ async def block_watchdog(self):
10641081

10651082
async def run_trigger(self, trigger_id, trigger):
10661083
"""Run a trigger (they are async generators) and push their events into our outbound event deque."""
1084+
if not os.environ.get("AIRFLOW_DISABLE_GREENBACK_PORTAL", "").lower() == "true":
1085+
try:
1086+
import greenback
1087+
1088+
await greenback.ensure_portal()
1089+
1090+
except ImportError:
1091+
log.warning("greenback unavailable; not creating portal.")
1092+
10671093
bind_log_contextvars(trigger_id=trigger_id)
10681094

10691095
name = self.triggers[trigger_id]["name"]

0 commit comments

Comments
 (0)