Skip to content

Create deferrable SqlExecuteQueryOperator compatible with Postgres#65618

Open
karenbraganz wants to merge 15 commits into
apache:mainfrom
karenbraganz:seqo_defer
Open

Create deferrable SqlExecuteQueryOperator compatible with Postgres#65618
karenbraganz wants to merge 15 commits into
apache:mainfrom
karenbraganz:seqo_defer

Conversation

@karenbraganz

Copy link
Copy Markdown
Collaborator

Was generative AI tooling used to co-author this PR?
  • Yes (please specify the tool below)

This PR modifies the SqlExecuteQueryOperator to be deferrable. I have also created a SqlExecuteQueryTrigger and added asynchronous functions to the DbApiHook for use with the SqlExecuteQueryOperator when it is deferred.

I plan on making this compatible with several database types. This PR only adds compatibility with Postgres.


  • 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 providers/common/sql/src/airflow/providers/common/sql/operators/sql.py Outdated
@jscheffl
jscheffl requested a review from Srabasti May 28, 2026 20:35
@Srabasti

Srabasti commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Thanks for incorporating the review changes for import of conf @karenbraganz !!!

Seeing that the 3 failing tests are related to docker failures and files not being found as below.
image
https://github.com/apache/airflow/actions/runs/26853708158/job/79193370724?pr=65618
https://github.com/apache/airflow/actions/runs/26853708158/job/79193370736?pr=65618
https://github.com/apache/airflow/actions/runs/26853708158/job/79193370689?pr=65618

Can you try rebasing and pushing the changes to repo, so as to ensure any bug fixes for unrelated failures are resolved by another open source contributor, automatically?

I observed @jscheffl pushed no files however CI ran fine, from log above last on May 29th. Looks to me, possibly some change happened after that to cause these errors to start failing.

FYI - @potiuk I see same error in failed CI run below. Looks to me the same issue.
https://github.com/apache/airflow/actions/runs/26858010209/job/79206609169?pr=67929

@potiuk potiuk added the ready for maintainer review Set after triaging when all criteria pass. label Jun 3, 2026
Comment thread providers/common/sql/src/airflow/providers/common/sql/operators/sql.py Outdated
@karenbraganz

Copy link
Copy Markdown
Collaborator Author

Sorry, I accidentally tangled up my branch and pushed the wrong commits, which is why all these reviews were requested. I have reverted the mistake.

Comment thread providers/common/sql/src/airflow/providers/common/sql/operators/sql.py Outdated
if self.fetch_results:
# Fetch the raw rows with the built-in handler and return them with the cursor
# descriptions; the operator applies any user handler on the worker.
results = await hook.run_async(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if the triggerer is killed in the middle of a run? Will this trigger be re-executed? Is there a chance that multiple instances of the same query are invoked?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, this could result in a duplicate query run if the trigger is killed. I can look into whether this can be avoided.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we can initiate on the worker and then poll on the triggerer? Not sure there's a straightforward way to do that.

We could also potentially block non-read-only queries by default and include a parameter to do things like INSERT, UPDATE, DELETE, etc with a docstring explaining the risks?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I looked into this. There isn't a straightforward way to implement this for Postgres. It requires the client side connection to remain alive in order to continue running the query. So we cannot open a connection from the worker to start the query, then close that, and re-open a new connection on the triggerer. Your second suggestion seems doable though:

We could also potentially block non-read-only queries by default and include a parameter to do things like INSERT, UPDATE, DELETE, etc with a docstring explaining the risks?

I can look into implementing it like that.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have added some logic for this. Still need to run tests and confirm that it is working as expected.


class SQLExecuteQueryTrigger(BaseTrigger):

class SQLGenericTransferTrigger(BaseTrigger):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a breaking change, right? If so, we'll need to bump the major version of this provider.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, this would qualify as a breaking change, so we should bump the major version FYI @kacpermuda

I do not anticipate a lot of disruption since only the trigger name is changed- not the operator name. This would only affect people who use this trigger in a custom operator.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there any other breaking changes in this PR? I think we discussed that for the default deferrable value we'll have a workaround to avoid breaking changes for now, so doing it just so that we can rename a class seems a bit ... pointless ? Not sure.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's pointless -- If someone built their own deferrable operator with SQLExecuteQueryTrigger, it will break.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not saying making a major release is pointless, just wondering if renaming a class is needed, trying to think of a way we can add this deferrable functionality as purely additive

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kacpermuda previously, the GenericTransfer operator used a trigger called the SqlExecuteQueryTrigger. Now that I am making the SqlExecuteQueryOperator deferrable, I thought it would be confusing to have a SqlExecuteQueryTrigger that is actually used by a different operator. I renamed the trigger used by the GenericTransfer operator to SqlGenericTransferTrigger and used the SqlExecuteQueryTrigger name for the trigger used by the SqlExecuteQueryOperator.

This name change is not required, but is good for consistency between the trigger and operator.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure sure, that makes sense, just wanted to make sure we're doing all the changes consciously since they lead to major release 😄

Comment thread providers/common/sql/src/airflow/providers/common/sql/triggers/sql.py Outdated
yield TriggerEvent({"status": "failure", "message": str(e)})


class SQLExecuteQueryTrigger(BaseTrigger):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer to see the GenericTransfer also use this SQLExecuteQueryTrigger, which is better suited due to it's more async native nature. I don't like the fact that we have now a dedicated trigger for the GenericTransfer, I think it should be possible to reuse the new SQLExecuteQueryTrigger.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense, I will look into how this can be implemented. @RNHTTR @kacpermuda we might be able to avoid releasing this in a major version if I do this since the trigger name for GenericTransfer won't change.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This to me stays a major change independently of this.

Comment thread providers/common/sql/src/airflow/providers/common/sql/triggers/sql.py Outdated
Comment thread providers/common/sql/src/airflow/providers/common/sql/hooks/sql.pyi Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants