Skip to content

Give each task its own start trigger arguments in standard sensors - #70888

Merged
potiuk merged 1 commit into
apache:mainfrom
potiuk:fix-start-trigger-args-shared-across-instances
Aug 1, 2026
Merged

Give each task its own start trigger arguments in standard sensors#70888
potiuk merged 1 commit into
apache:mainfrom
potiuk:fix-start-trigger-args-shared-across-instances

Conversation

@potiuk

@potiuk potiuk commented Aug 1, 2026

Copy link
Copy Markdown
Member

start_trigger_args is a class attribute on DateTimeSensorAsync, TimeSensor and
FileSensor, and each one assigned through it in __init__:

self.start_trigger_args.trigger_kwargs = dict(moment=self._moment, ...)

That mutates the shared class-level object instead of creating an instance attribute, so
every task built from the operator ends up advertising the arguments of whichever task was
constructed last.

Reproducer on main:

a = DateTimeSensorAsync(task_id="a", target_time=datetime(2030, 1, 1), start_from_trigger=True)
b = DateTimeSensorAsync(task_id="b", target_time=datetime(2040, 6, 6), start_from_trigger=True)

a.start_trigger_args is b.start_trigger_args        # True
a.start_trigger_args.trigger_kwargs["moment"]       # 2040-06-06  <- b's moment

With start_from_trigger=True the task starts directly in the triggerer from these
arguments, so two DateTimeSensorAsync tasks in one Dag both wait for the same moment. The
same applies to TimeSensor's moment and to FileSensor's filepath, recursive,
poke_interval and timeout.

Each sensor now replaces start_trigger_args with a fresh copy via dataclasses.replace,
which binds an instance attribute and leaves the class-level template untouched for the next
task built from it.

Regression tests are added for all three sensors; each fails on main.


Was generative AI tooling used to co-author this PR?
  • Yes — Claude Code (Opus 5)

Generated-by: Claude Code (Opus 5) following the guidelines

start_trigger_args is a class attribute, so assigning through it in
__init__ overwrote the arguments shared by every other task built from
the same operator. Two DateTimeSensorAsync tasks in one Dag both waited
for whichever moment was constructed last, and the same applied to
TimeSensor's moment and FileSensor's path and timeout.
@potiuk
potiuk requested review from jroachgolf84 and shahar1 August 1, 2026 01:59
@potiuk potiuk added this to the Airflow 3.3.1 milestone Aug 1, 2026
@potiuk potiuk added the backport-to-v3-3-test Backport to v3-3-test label Aug 1, 2026
@potiuk
potiuk merged commit 16b4e62 into apache:main Aug 1, 2026
155 checks passed
@potiuk
potiuk deleted the fix-start-trigger-args-shared-across-instances branch August 1, 2026 20:47
@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Backport failed to create: v3-3-test. View the failure log Run details

Note: As of Merging PRs targeted for Airflow 3.X
the committer who merges the PR is responsible for backporting the PRs that are bug fixes (generally speaking) to the maintenance branches.

In matter of doubt please ask in #release-management Slack channel.

Status Branch Result
v3-3-test Commit Link

You can attempt to backport this manually by running:

cherry_picker 16b4e62 v3-3-test

This should apply the commit to the v3-3-test branch and leave the commit in conflict state marking
the files that need manual conflict resolution.

After you have resolved the conflicts, you can continue the backport process by running:

cherry_picker --continue

If you don't have cherry-picker installed, see the installation guide.

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.

3 participants