This is an automated email from the ASF dual-hosted git repository.

amoghrajesh pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/main by this push:
     new 7a531a9dcac Add support for operators that achieve durable execution 
manually in registry (#70291)
7a531a9dcac is described below

commit 7a531a9dcacb732e54796579901cc3c3f9653b19
Author: Amogh Desai <[email protected]>
AuthorDate: Fri Jul 24 13:34:20 2026 +0530

    Add support for operators that achieve durable execution manually in 
registry (#70291)
---
 dev/registry/extract_parameters.py            | 26 ++++++++++++++++++++++----
 dev/registry/tests/test_extract_parameters.py | 24 ++++++++++++++++++++++++
 2 files changed, 46 insertions(+), 4 deletions(-)

diff --git a/dev/registry/extract_parameters.py 
b/dev/registry/extract_parameters.py
index 0e9eff89a4d..e32b06bae7a 100644
--- a/dev/registry/extract_parameters.py
+++ b/dev/registry/extract_parameters.py
@@ -386,11 +386,29 @@ def load_resumable_job_mixin() -> type | None:
 
 
 def is_durable_capable(cls: type, resumable_mixin: type | None) -> bool:
-    """Return True if a class fully implements ResumableJobMixin's 
crash-recovery contract.
-
-    Inheriting the mixin is not sufficient: a complete override is inert unless
-    execute() actually calls execute_resumable().
+    """Return True if a class implements durable/crash-safe execution.
+
+    Two ways to qualify:
+    1. A class-level `__supports_durable_execution = True`
+    declaration (for operators that implement this directly against
+    task_state_store, without ResumableJobMixin -- e.g. KubernetesPodOperator,
+    AgentOperator).
+    2. Genuinely implementing ResumableJobMixin's contract.
+
+    The first path deliberately looks up the class prefixed attribute
+    (`_{ClassName}__supports_durable_execution`) rather than a fixed string.
+    A subclass that overrides execute() itself (e.g. SparkKubernetesOperator)
+    may not preserve the parent's task_state_store reconnect behavior, so the
+    declaration must not be inherited -- only the exact class that wrote
+    `__supports_durable_execution` in its own body qualifies this way.
+
+    Inheriting the mixin alone is not sufficient for the second path: a
+    complete override is inert unless execute() actually calls
+    execute_resumable().
     """
+    if getattr(cls, f"_{cls.__name__}__supports_durable_execution", None) is 
True:
+        return True
+
     if resumable_mixin is None or resumable_mixin not in cls.__mro__:
         return False
 
diff --git a/dev/registry/tests/test_extract_parameters.py 
b/dev/registry/tests/test_extract_parameters.py
index be0f608e17e..2cdb0953229 100644
--- a/dev/registry/tests/test_extract_parameters.py
+++ b/dev/registry/tests/test_extract_parameters.py
@@ -225,6 +225,24 @@ class PlainOperator:
         return None
 
 
+class ManuallyDurableOperator:
+    """Implements durable execution directly (e.g. via task_state_store), 
without
+    ResumableJobMixin -- mirrors KubernetesPodOperator/AgentOperator."""
+
+    __supports_durable_execution = True
+
+    def execute(self, context):
+        return None
+
+
+class ManuallyDurableSubclass(ManuallyDurableOperator):
+    """Overrides execute() itself -- must NOT inherit the parent's declaration,
+    since nothing here verifies it preserves the reconnect behavior."""
+
+    def execute(self, context):
+        return "something else entirely"
+
+
 class TestIsDurableCapable:
     def test_fully_implemented_and_wired_qualifies(self):
         assert is_durable_capable(FullyImplementedResumableOperator, 
FakeResumableJobMixin) is True
@@ -241,6 +259,12 @@ class TestIsDurableCapable:
     def test_mixin_unavailable_disqualifies(self):
         assert is_durable_capable(FullyImplementedResumableOperator, None) is 
False
 
+    def test_manual_durable_marker_qualifies_without_mixin(self):
+        assert is_durable_capable(ManuallyDurableOperator, None) is True
+
+    def test_subclass_not_redeclaring_marker_disqualifies(self):
+        assert is_durable_capable(ManuallyDurableSubclass, 
FakeResumableJobMixin) is False
+
 
 # ---------------------------------------------------------------------------
 # Module dataclass

Reply via email to