Skip to content

Add durable/deferrable filters to the Airflow Registry - #70298

Draft
amoghrajesh wants to merge 3 commits into
apache:mainfrom
astronomer:filtering-as-durable-on-registry
Draft

Add durable/deferrable filters to the Airflow Registry#70298
amoghrajesh wants to merge 3 commits into
apache:mainfrom
astronomer:filtering-as-durable-on-registry

Conversation

@amoghrajesh

Copy link
Copy Markdown
Contributor

Was generative AI tooling used to co-author this PR?
  • Yes - claude sonnet 4.6

Important Note

What "durable" and "deferrable" mean in the PR: there are two different reasons an operator can survive a crash, and they work in totally different ways. "Durable" means the operator own code remembers where its job was and reconnects to it instead of starting over, and this operates using task state store in synchronous mode. "Deferrable" is running using a trigger, in asynchronous mode. The end result looks similar to a user (nothing gets redone), but one is a promise the operator has to keep and the other is just how the system already works for everyone.

What

Follow up to the merged supports_durable_execution badge PR (#67236). Now that we have badget support, we should also have a few filters for ease of navigation for two related-but-distinct capabilities: "durable" (anything that survives a crash without redoing work -- ResumableJobMixin/manual-marker operators, or deferrable ones) and "deferrable" (the narrower, deferrable-only subset). The registry had no deferrable detection at all before this change.

Current behaviour

The Registry only tracks supports_durable_execution (ResumableJobMixin or the manual __supports_durable_execution marker coming in PR: #70291). Deferrable operators -- a much more common capability across most cloud providers -- have no signal anywhere in the pipeline, and there's no way to filter a provider's module list by either capability.

Proposed change

  • Detection: supports_deferrable(cls) added to dev/registry/extract_parameters.py -- checks for a deferrable constructor parameter, reusing the existing get_params_from_class() machinery already used for parameters.json (no new introspection needed).
  • Schema: supports_deferrable: bool = False added to ModuleContract, wired into make_entry() alongside supports_durable_execution (14 fields total, kept as an independent signal, not merged into the existing one).
  • Frontend: two independent badges on module cards ("Durable", "Deferrable": teal/blue) shown per their own signal, since an operator can have either, both, or neither. Two filter toggles on a provider's module list: "Durable (includes deferrable)" and "Deferrable only".

Changes of Note

  • The two filters are a deliberate union/subset pair, not independent booleans. "Durable" is supports_durable_execution OR supports_deferrable -- checking it shows every deferrable operator plus every ResumableJobMixin/manual-marker operator, even ones that aren't deferrable. "Deferrable only" is supports_deferrable alone, never OR'd. This means an operator that is both durable and deferrable appears under both filters -- verified this is intentional and not confusing in practice, since the two independent badges on the card explain why.
  • The checkbox labels ("Durable (includes deferrable)" / "Deferrable only") were chosen specifically to make that asymmetric containment relationship (deferrable durable, never the reverse) visible at the point of clicking, rather than relying on a tooltip or a caption someone could miss.
  • is_deferrable inheriting a parent's __init__ unmodified still counts as deferrable (unlike the supports_durable_execution manual-marker case, which deliberately does not propagate to subclasses) -- inheriting an unmodified constructor is a real functional guarantee the parameter still works, whereas inheriting a durable-execution claim says nothing about whether an overridden execute() still preserves it.

Testing

  • Built breeze to extract the provider data using: breeze registry extract-data

  • Built the actual Eleventy site against this real data and confirmed in the rendered HTML: both badges appear on the right operator cards (e.g. Databricks' page shows both a "Durable" and "Deferrable" badge on DatabricksRunNowOperator), both filter checkboxes render with the intended labels, and the data-durable/data-deferrable attributes are correctly populated per the OR/non-OR logic on every module checked.

For current changes, this is the behaviour:

  • Databricks: DatabricksSubmitRunOperator and DatabricksRunNowOperator are both durable and deferrable. DatabricksNotebookOperator, DatabricksSQLStatementsOperator, DatabricksTaskBaseOperator, DatabricksTaskOperator, and DatabricksSQLStatementsSensor are deferrable only. The rest of the provider's operators/hooks/sensors are neither.
  • Apache Spark: SparkSubmitOperator is durable but not deferrable (no deferrable param) -- this is the single durable-only case across the entire registry.
  • Google/BigQuery: BigQueryInsertJobOperator is both durable and deferrable, same pattern as Databricks.
  • Amazon/Redshift: RedshiftDataOperator is both durable and deferrable.
  • Snowflake: SnowflakeSqlApiOperator is both durable and deferrable.

Across the full dataset: 1779 modules total, 6 durable, 217 deferrable, 5 with both (the five listed above).

Some screenshots:

In this image, "Durable (includes deferrable)" is selected, and you can see both durable + deferrable (BigQueryInsertJobOperator) and just deferrable ones selected

image

"Deferrable only selection":

image

Operator like snowflake has only one operator with both deferrable and durable property, so its here:

image

Spark is one of few operators with only "durable", and no deferrable option:

image

What's next

Interactive click-through verification (actually toggling the checkboxes in a running browser to confirm filterModules() behaves correctly) hasn't been done -- only the generated HTML/data have been checked, not runtime JS behavior. Registry-wide (cross-provider) discovery -- "which are all the durable/deferrable operators across the whole registry," via a Pagefind search filter facet -- was discussed and deliberately deferred to a separate follow-up.


  • Read the Pull Request Guidelines for more information. Note: commit author/co-author name and email in commits become permanently public when merged.
  • For fundamental code changes, an Airflow Improvement Proposal (AIP) is needed.
  • When adding dependency, check compliance with the ASF 3rd Party License Policy.
  • For significant user-facing changes create newsfragment: {pr_number}.significant.rst, in airflow-core/newsfragments. You can add this file in a follow-up commit after the PR is created so you know the PR number.

Comment thread dev/registry/extract_parameters.py Outdated
@amoghrajesh
amoghrajesh requested a review from ashb July 24, 2026 08:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: In progress
Status: In progress

Development

Successfully merging this pull request may close these issues.

2 participants