GitHub user kinqsradio added a comment to the discussion: Task retries after 
approval expiry: reconciling a committed export without authorising a new one

Yes, keeping that decision inside the task is the right place, because Airflow 
has no notion of "this side effect already happened" or "this attempt is 
authorised". A retry, a manual clear and a re-trigger are all just "run the 
callable again" to the scheduler. Clearing resets the task instance state so 
it's scheduled again, and nothing more. So your rule that clearing doesn't 
grant permission for a new export holds automatically, as long as the callable 
checks the operation record first. The [best 
practices](https://airflow.apache.org/docs/apache-airflow/stable/best-practices.html)
 say the same thing more generally: tasks should be idempotent, and Airflow 
won't do it for you.

A few points worth adding to the design:

- **Make the check-and-write atomic, not just ordered.** On a distributed 
executor, a task whose heartbeat is lost can be marked failed and retried while 
the first process is still running. "Check for the operation, then write" in 
two steps can then produce two exports. A unique constraint on the operation ID 
in the same transaction as the export makes the second writer fail instead of 
duplicating. You get this for free in SQLite. Make sure the real sink has an 
equivalent (a unique key, a conditional put, or an idempotency key on the 
external API).
- **Keep the operation ID out of Airflow's run identity.** You already avoid 
`try_number`. The same goes for `run_id` and the logical date if a new approved 
export should get a new ID. Passing the ID in via `params` or `dag_run.conf` 
(or reading it from the approval) means a re-triggered run with the same ID 
reconciles, and a new export needs a new approval, which is what you described.
- **Decide what "reconciled" returns.** If downstream tasks pull an XCom from 
this task, make `RECONCILED_EXISTING` return the same payload as the original 
success, so a cleared-and-reconciled run looks the same downstream.
- **External sinks:** for a sink you can't write to transactionally, the usual 
pattern is write-ahead: record "intent" with the operation ID, perform the 
export using that ID as the idempotency key, then mark it committed. A retry 
that finds "intent" without "committed" asks the sink whether that ID exists, 
instead of re-checking the approval.

I'm not aware of an Airflow example that covers the expiring-approval part 
specifically. Most examples stop at idempotent writes.


GitHub link: 
https://github.com/apache/airflow/discussions/76421#discussioncomment-19431678

----
This is an automatically sent email for [email protected].
To unsubscribe, please send an email to: [email protected]

Reply via email to