From 32c9312fcbc21ed9dc7d276c892c8e843ec0ecce Mon Sep 17 00:00:00 2001 From: Nick Mills-Barrett Date: Tue, 4 Feb 2025 21:40:42 +0000 Subject: [PATCH] api: don't execute callbacks within a greenlet if we're already in one Prevents infinite recursion when the loacl context is lost when switching between greenlets. --- pyinfra/api/command.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/pyinfra/api/command.py b/pyinfra/api/command.py index f9f78c751..aba3204d7 100644 --- a/pyinfra/api/command.py +++ b/pyinfra/api/command.py @@ -8,7 +8,7 @@ import gevent from typing_extensions import Unpack -from pyinfra.context import ctx_config, ctx_host +from pyinfra.context import LocalContextObject, ctx_config, ctx_host from .arguments import ConnectorArguments @@ -225,6 +225,12 @@ def execute(self, state: "State", host: "Host", connector_arguments: ConnectorAr if "state" in argspec.args and "host" in argspec.args: return self.function(state, host, *self.args, **self.kwargs) + # If we're already running inside a greenlet (ie a nested callback) just execute the func + # without any gevent.spawn which will break the local host object. + if isinstance(host, LocalContextObject): + self.function(*self.args, **self.kwargs) + return + def execute_function(): with ctx_config.use(state.config.copy()): with ctx_host.use(host):