Abolfazlrwm opened a new pull request, #76627:
URL: https://github.com/apache/airflow/pull/76627
closes: #55432
## Problem
Extra operator links are currently resolved through XCom for every task
instance, regardless of whether the URL actually depends on the run. A link
whose URL is constant (docs, dashboards, consoles) still requires the task to
push an XCom entry in `finalize()`, and the API server to read it back.
Consequences:
- a link that was never pushed renders empty - e.g. for failed or
still-running task instances (reported in #55432);
- every task execution pays an XCom write per link even when the URL is a
constant.
## Root cause
The serialized DAG encodes extra links only as `{link_name: xcom_key}`
(`_serialize_operator_extra_links`), and the API server always deserializes
them into `XComOperatorLink`, whose `get_link()` reads the URL from XCom. There
is no place in the serialization format for a run-independent URL.
This is why PR #70343 (which introduced the Task-SDK-only `static_url`
override and skipped the XCom push) was closed: without a serialization change,
skipping the push makes the link render empty in the UI. I rebuilt the approach
on top of that feedback - happy to adjust further.
## Fix
1. **task-sdk** - `BaseOperatorLink` gains an optional `static_url` property
(defaults to `None`); `get_link()` falls back to it, so subclasses with a
constant URL no longer need to implement `get_link()`. `finalize()` skips the
XCom push for links that declare `static_url`.
2. **serialization** - static links are encoded as `{link_name:
{"static_url": ...}}` (dynamic links keep `{link_name: xcom_key}`);
deserialization produces a new `StaticOperatorLink` that returns the stored URL
without touching XCom. Old blobs (plain string entries) keep deserializing
exactly as before.
3. **SERIALIZER_VERSION 3 -> 4** - so readers older than this change reject
new blobs loudly instead of misreading static entries as XCom keys;
`dag_version_diff`'s supported set and canonicalization chain follow the bump,
and the TS SDK version pin is updated.
The UI needs no change: the links endpoint resolves links via
`SerializedBaseOperator.get_extra_links()`, which now returns the constant URL
directly.
## Tests
- task-sdk: `test_task_run_with_static_operator_extra_link` and
`test_finalize_with_mixed_operator_extra_links` assert that static links are
not pushed to XCom while dynamic links still are (the gap that sank #70343).
- core: `test_static_operator_link_returns_url_without_xcom` and
`test_static_operator_extra_link_roundtrip` (encode + decode + render without
XCom).
- API: `test_should_respond_200_static_link_without_xcom` renders the link
through `GET /dags/{dag_id}/dagRuns/{run_id}/taskInstances/{task_id}/links`
with zero XCom rows - the UI-rendering requirement from #70343's closing review.
All affected test files pass locally (Python 3.11, SQLite):
`test_task_runner.py` 595 passed, `test_dag_serialization.py` 263 passed,
`test_dag_version_diff.py` 565 passed, `test_extra_links.py` 29 passed, plus
`test_operatorlink.py` and `test_ts_sdk_serialization_version.py`. `pre-commit
run --files` passes for ruff/ruff-format on the changed files; several
repo-local script hooks (rich/yaml/astor importers, exec-bit checks) fail in my
sandbox on untouched files as well, so I could not run them here - CI will
cover them.
## Docs
New "Static operator extra links" section in
`airflow-core/docs/howto/define-extra-link.rst`.
---
##### Was generative AI tooling used to co-author this PR?
- [X] Yes (please specify the tool below)
Generated-by: Z.ai GLM following [the
guidelines](https://github.com/apache/airflow/blob/main/contributing-docs/05_pull_requests.rst#gen-ai-assisted-contributions)
--
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]