1fanwang opened a new pull request, #71518:
URL: https://github.com/apache/airflow/pull/71518

   Operator extra links are cached as XCom rows under the link's `xcom_key`, 
which carries no
   attempt. `XComOperatorLink.get_link` receives a `TaskInstanceKey` and 
ignores its
   `try_number`, so once a task retries, asking for an earlier attempt's link 
hands back the
   latest attempt's URL.
   
   #65661 made the extra-links endpoint resolve the requested attempt, which is 
what makes the
   wrong answer reachable: the UI can now ask for attempt 1 and gets attempt 
2's link, pointing
   at the wrong logs. The retry also clears the task's XComs, so nothing older 
survives to
   resolve against.
   
   It matters most when the URL cannot be recomputed — a job id the remote 
service mints per
   submission, so each attempt gets a different one. Providers linking to 
per-attempt logs in
   EMR, Glue, Databricks, Dataproc and Livy are all in this shape.
   
   The worker now also caches the link under a key carrying the attempt that 
produced it, and
   the reader prefers that row, falling back to the bare key so links written 
before this
   change still resolve. Those rows are exempt from the clear a retry issues, 
since they
   describe attempts that already ran. The prefix is owned by Airflow rather 
than derived from
   the link's `xcom_key`, because a link may override that with any name, as 
the Databricks and
   Google links do.
   
   This is one of the shapes I floated on the issue and the smallest I could 
find. Happy to
   rework it if you would rather give `xcom_key` access to `ti_key`, or put 
links on the task
   state store alongside the durable-execution work in #69914 and #71211.
   
   closes: #71471
   
   ## Testing
   
   The regression is in `XComOperatorLink.get_link`, so I ran that class 
against a real
   metastore with three rows — attempt 1's link, attempt 2's link, and the bare 
key — asking it
   for each attempt, before and after the change.
   
   <details><summary>Raw output</summary>
   
   Before, on 3.2.2. Attempt 1 resolves to attempt 2's URL:
   
   ```
   $ python read_test.py
     try 1 -> https://logs/attempt-2
     try 2 -> https://logs/attempt-2
   ```
   
   After:
   
   ```
   $ python read_test.py
     try 1 -> https://logs/attempt-1
     try 2 -> https://logs/attempt-2
   ```
   
   The purge predicate was checked separately against a table of keys, 
including ones that
   would be spared if the `_` in the prefix were left as a LIKE wildcard:
   
   ```
   spared : ['_link_attempt_1__link_Foo', 
'_link_attempt_2_databricks_job_run_link']
   cleared: ['_link_Foo', 'databricks_job_run_link', 'return_value',
             'Xlink_attemptX1_y', 'my_link_attempt_1_thing']
   ```
   
   </details>
   
   Added tests cover all three sides: the reader prefers the requested attempt 
and falls back
   to the bare key, and the run endpoint keeps the per-attempt rows out of
   `xcom_keys_to_clear`. I could not run the suite locally, so I am relying on 
CI for it.
   


-- 
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: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to