You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airflow.apache.org by "1fanwang (via GitHub)" <gi...@apache.org> on 2026/08/11 22:20:57 UTC

[I] Operator extra links from earlier attempts are deleted on retry [airflow]

1fanwang opened a new issue, #71471:
URL: https://github.com/apache/airflow/issues/71471

   ### Apache Airflow version
   
   3.2.2
   
   ### What happened?
   
   Operator extra links are backed by XCom rows. `BaseOperatorLink.xcom_key` defaults to
   `_link_<ClassName>`, and `get_link()` is handed a `TaskInstanceKey` that carries a
   `try_number`.
   
   When a task instance transitions to running, the execution API collects **every** XCom key
   for that task instance into `TIRunContext.xcom_keys_to_clear`, and the worker deletes each
   one. There is no filter — the only exemption is deferral:
   
   https://github.com/apache/airflow/blob/537feafb3697338b3988d826b9c9b45da06b1f23/airflow-core/src/airflow/api_fastapi/execution_api/routes/task_instances.py#L285-L293
   
   So a retry deletes the `_link_*` rows written by every previous attempt. An extra link can
   only ever resolve for the attempt that ran last.
   
   This collides with a change that shipped in the same release. #65661 (closing #65354) made
   the extra-links endpoint try-aware: pass `try_number` and it resolves the link against that
   attempt's `TaskInstanceHistory`. The read path now asks for attempt N's link while the
   write path guarantees only the latest attempt's row exists, so for any earlier attempt the
   endpoint returns nothing.
   
   It bites hardest when the external URL cannot be recomputed — a job id the remote service
   mints per submission, so each attempt gets a different one. Once the row is gone the link
   to that attempt's logs is unrecoverable. Providers linking to per-attempt logs in EMR,
   Glue, Databricks, Dataproc or Livy are all in this shape; none of them stores anything
   per-attempt today, so the older attempts' links are simply lost.
   
   There is also no way to work around it in a link class. `xcom_key` is a plain property with
   no access to `ti_key`, so the framework's own fetch cannot vary by attempt; the `xcom` table
   has no `try_number` column, so per-attempt rows can only be expressed by encoding the try
   into the key string; and the collection above takes every key regardless, so an encoded key
   is deleted too.
   
   I'm not proposing a shape — the options trade off against each other and the call is yours.
   Exempting a key prefix from the collection is the smallest. Giving `xcom_key` access to
   `ti_key` would make per-attempt links first class but changes a public interface. Pointing
   links at the task state store fits where durable cross-retry state is already heading
   (#69914, #71211), but that store is aimed at job identity rather than link rendering.
   
   Happy to put up a PR once there's a preferred direction.
   
   ### What you think should happen instead?
   
   An extra link resolved for attempt N should return attempt N's URL, which is what the
   try-aware endpoint added in #65661 implies.
   
   ### How to reproduce
   
   1. Use any operator with an extra link whose URL is built from a value pushed at runtime
      (`_link_<ClassName>`), or push the key by hand.
   2. Let attempt 1 run and write it.
   3. Make the task fail so it retries.
   4. While attempt 2 is running, query the metastore:
   
   ```sql
   SELECT `key` FROM xcom WHERE dag_id = '<dag>' AND task_id = '<task>' AND run_id = '<run>';
   ```
   
   Only attempt 2's `_link_*` row is present. Requesting the link for `try_number=1` through
   the extra-links endpoint returns nothing.
   
   ### Operating System
   
   Linux
   
   ### Versions of Apache Airflow Providers
   
   Not provider specific — the behaviour is in airflow-core.
   
   ### Deployment
   
   Official Apache Airflow Helm Chart
   
   ### Deployment details
   
   Reproduced on 3.2.2 with the KubernetesExecutor and a MySQL metastore. The code path is
   unchanged on `main` at 537feafb3697338b3988d826b9c9b45da06b1f23.
   
   ### Are you willing to submit PR?
   
   - [X] Yes I am willing to submit a PR!
   
   ### Code of Conduct
   
   - [X] I agree to follow this project's [Code of Conduct](https://github.com/apache/airflow/blob/main/CODE_OF_CONDUCT.md)
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@airflow.apache.org.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org