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]
