Visitar URL original
Improve error message for BranchPythonOperator when no task_id to follow by eladkal · Pull Request #18471 · apache/airflow · GitHub
Skip to content

Improve error message for BranchPythonOperator when no task_id to follow - #18471

Merged
eladkal merged 3 commits into
apache:mainfrom
eladkal:python
Sep 25, 2021
Merged

eladkal merged 3 commits into
apache:mainfrom
eladkal:python

Conversation

@eladkal

@eladkal eladkal commented Sep 23, 2021

Copy link
Copy Markdown
Contributor

closes: #18454


^ Add meaningful description above

Read the Pull Request Guidelines for more information.
In case of fundamental code change, Airflow Improvement Proposal (AIP) is needed.
In case of a new dependency, check compliance with the ASF 3rd Party License Policy.
In case of backwards incompatible changes please leave a note in UPDATING.md.

@uranusjr

uranusjr commented Sep 23, 2021 •

Copy link
Copy Markdown
Member

Instead of explicitly forbidding this, would it be reasonable to handle the None case and skip all the downstreams instead?

@eladkal

eladkal commented Sep 23, 2021

Copy link
Copy Markdown
Contributor Author

Instead of explicitly forbidding this, would it be reasonable to handle the None case and skip all the downstreams instead?

When would None be desired?

@josh-fell

josh-fell commented Sep 23, 2021 •

Copy link
Copy Markdown
Contributor

Instead of explicitly forbidding this, would it be reasonable to handle the None case and skip all the downstreams instead?

When would None be desired?

I could understand users may not want the DAG to fail outright if the branching section is not critical path like with some feature engineering use cases I've seen. It may be more intuitive to not have to create an empty branch to simply continue with the pipeline if an output doesn't need to be tracked. An edge case for sure with an obvious workaround.

Could this be a configurable mode: fail or skip if no branches found?

@eladkal

eladkal commented Sep 23, 2021

Copy link
Copy Markdown
Contributor Author

I could understand users may not want the DAG to fail outright if the branching section is not critical path like with some feature engineering use cases I've seen. It may be more intuitive to not have to create an empty branch to simply continue with the pipeline if an output doesn't need to be tracked. An edge case for sure with an obvious workaround.

Could this be a configurable mode: fail or skip if no branches found?

This sounds more like a wrong usage of branching. For conditional junctions we have ShortCircuitOperator
but i'm OK with @uranusjr suggestion if this is prefered.

@josh-fell

Copy link
Copy Markdown
Contributor

Perhaps but the ShortCircuitOperator can be redundant here if we're skipping downstream tasks with this operator now. Seconded on @uranusjr's suggestion as well FWIW.

@MatrixManAtYrService

MatrixManAtYrService commented Sep 23, 2021 •

Copy link
Copy Markdown
Contributor

I had the same thought as @uranusjr, skipping all downstream tasks seems like an obvious way to interpret None to me, like an if statement with no else.

I'm not gonna fight for it though. Scope creep is real and I'll be happy enough to have a better error.

@eladkal

eladkal commented Sep 23, 2021 •

Copy link
Copy Markdown
Contributor Author

@uranusjr correct me if I'm wrong but this requires rewriting skip_all_except
The way I see it I can't just blindly skip all downstream tasks as unlike ShortCircuitOperator branching does respect trigger rules so I need to skip all downstream tasks until a join/junction task is found.
Since my input is None we need to search if such junction exists.
So I need to set difference between two cases:

If I have a case of:

        # branch  ----->  task2
        #   \           
        #    \        
        #       task1

Then I need to execute skip
but If I have a case like:

        # branch  ----->  task2   <----- task3
        #   \           
        #    \        
        #       task1

Then I need to run skip_all_except(context['ti'],['task2]) because task2 may still run depends on its trigger_rule.

@ashb

ashb commented Sep 23, 2021

Copy link
Copy Markdown
Member

If you want to skip everything you can raise AirflowSkipException I think. (that would have a slightly different behaviour of also skipping the branch op itself, unless we caught that in this op and turned it in to skip all downstream)

That's all a separate pr/feature though

@eladkal

eladkal commented Sep 24, 2021

Copy link
Copy Markdown
Contributor Author

If you want to skip everything you can raise AirflowSkipException I think. (that would have a slightly different behaviour of also skipping the branch op itself, unless we caught that in this op and turned it in to skip all downstream)

So this is a possible route. We will need to keep the change in SkipMixin itself to avoid changing all the branch operators.

That's all a separate pr/feature though

I agree. This PR is just replacing the error message to a more meaningful one. There is no change in functionality here.
I'll work on trying to solve the issue from the root for a future PR.

Comment thread airflow/operators/python.py Outdated
Comment on lines 181 to 182

@uranusjr uranusjr Sep 24, 2021 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Kind of wondering whether we should check for all non-str values. Or even check the value is a valid task ID? Something like…

if isinstance(branch, str):
    branches = [branch]
try:
    branches = list(branch)  # Check iterability.
except TypeError:
    raise AirflowException("Branch callable must return either a task ID or a list of IDs")
valid_task_ids = set(context["dag"].task_ids)
if not any(b in valid_task_ids for b in branches):
    raise AirflowException("Branch callable must return at least one task ID to follow")

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

yeah this is something I had in mind - added it in last commit
In general this is something we should have in skipmixin as it's logic shared by all branch operators.

@github-actions

Copy link
Copy Markdown
Contributor

The PR most likely needs to run full matrix of tests because it modifies parts of the core of Airflow. However, committers might decide to merge it quickly and take the risk. If they don't merge it quickly - please rebase it to the latest main at your convenience, or amend the last commit of the PR, and push it with --force-with-lease.

@github-actions github-actions Bot added the full tests needed We need to run full set of tests for this PR to merge label Sep 24, 2021
Comment thread airflow/operators/python.py Resolved
@eladkal eladkal added this to the Airflow 2.2.0 milestone Sep 24, 2021
def execute(self, context: Dict):
branch = super().execute(context)
# TODO: The logic should be moved to SkipMixin to be available to all branch operators.
if isinstance(branch, str):

@potiuk potiuk Sep 25, 2021 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should we also change SkipMixin while we are changing it (or will it be a separate PR) ? (per the comment above)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Seperate PR.
I will work on it. We want also to change the functionality so it will accept None and skip all downstream tasks (untill a junction/join task).

@eladkal
eladkal merged commit c1578fb into apache:main Sep 25, 2021
@eladkal
eladkal deleted the python branch September 25, 2021 17:55
invalid_task_ids = branches - valid_task_ids
if invalid_task_ids:
raise AirflowException(
f"Branch callable must valid task_ids. Invalid tasks found: {invalid_task_ids}"

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.

@eladkal Did you mean something like
Branch callable must *return* valid task_ids?

@eladkal eladkal Sep 29, 2021 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Ah yeah. Ill raise a PR to fix it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

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.

LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

full tests needed We need to run full set of tests for this PR to merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

BranchPythonOperator intermittently fails to find its downstream task ids

7 participants