Remove unmap method from scheduler-side - #54816

Merged
kaxil merged 1 commit into
apache:mainfrom
astronomer:remove-unmap-from-scheduler
Aug 23, 2025
Merged

Remove unmap method from scheduler-side#54816
kaxil merged 1 commit into
apache:mainfrom
astronomer:remove-unmap-from-scheduler

Conversation

@kaxil

Copy link
Copy Markdown
Member

The scheduler-side MappedOperator and SerializedBaseOperator classes contained unmap() functionality that was creating unnecessary complexity and architectural confusion. The unmap() method was attempting to synthesize "real" operators from serialized data, but this is not needed for scheduler operations.

Scheduler doesn't execute callbacks - that's handled by the DAG processor. So simplifying the codebase.

This would also be helpful for #54569

Remove unnecessary unmap() functionality from server-side operators to
simplify scheduler architecture and eliminate synthetic operator creation.
Key changes:
- Remove unmap() method from MappedOperator class
- Update TaskInstance.fetch_handle_failure_context() to use original task directly
- Remove unmap() call from SerializedBaseOperator.get_extra_links()
- Update related tests to verify serialization without unmap functionality
The scheduler no longer needs to 'unmap' operators since:
- Callbacks are handled by DAG processor, not scheduler
- Email settings and fail-fast logic work with original task
- Extra links work consistently between regular and mapped operators
This eliminates the TODO comment about moving runtime unmap to task runner
and provides cleaner separation between scheduler and execution concerns.
Includes pre-commit formatting fixes applied by ruff and ruff-format.
Comment on lines -1312 to +1311
return link.get_link(self.unmap(None), ti_key=ti.key) # type: ignore[arg-type] # TODO: GH-52141 - BaseOperatorLink.get_link expects BaseOperator but receives SerializedBaseOperator
return link.get_link(self, ti_key=ti.key) # type: ignore[arg-type] # TODO: GH-52141 - BaseOperatorLink.get_link expects BaseOperator but receives SerializedBaseOperator

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I wonder if this should be kept. Would users expect get_link to be called against a MappedOperator? It may not have the same attributes as the underlying operator.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

models.MappedOperator also defines def get_extra_links -- so either is already broken or there should be no change with this on it 🤷

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

defget_extra_links(self, ti: TaskInstance, name: str) ->str|None:
"""
For an operator, gets the URLs that the ``extra_links`` entry points to.
:meta private:
:raise ValueError: The error message of a ValueError will be passed on through to
the fronted to show up as a tooltip on the disabled link.
:param ti: The TaskInstance for the URL being searched for.
:param name: The name of the link we're looking for the URL for. Should be
one of the options specified in ``extra_links``.
"""
link=self.operator_extra_link_dict.get(name) orself.global_operator_extra_link_dict.get(name)
ifnotlink:
returnNone
returnlink.get_link(self, ti_key=ti.key) # type: ignore[arg-type] # TODO: GH-52141 - BaseOperatorLink.get_link expects BaseOperator but receives MappedOperator

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With 3.0.0 get links aren't called in the scheduler or really the webserver anymore - we get the link in the execution side and store it in the xcom as an XComExtraLink (or something like that)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this only gets called for plugin registered global links.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually I think this was from a series of incorrect changes… get_link used to only accept BaseOperator before this change
#46613

You can see get_extra_links always calls unmap to get a BaseOperator.

After the PR above, get_extra_links was then incorrectly “restored” to pass in MappedOperator in #50238. This PR has not been a release yet.

I think removing unmap here is therefore wrong. It should be kept for get_extra_links for compatibility.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@uranusjr#46613 is released in 3.0.0 and #50238 in 3.0.1

get_link used to only accept BaseOperator before this change

How would that work with CustomOperators though! We don't serialize all attributes so extra_links with operator as argument will have limited attributes to work with for global op links

@uranusjruranusjrAug 27, 2025

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the thing was original designed we could get the original operator class from a dag bag… but yeah I guess all these no longer apply now.

Now that we always do get_link in the worker (#54816 (comment)), we can always get the original operator class (you need to unmap for execution anyway), so I guess what we need to do is

  1. This PR is OK, we don’t need unmap at scheduler side
  2. Not have extra_links and get_extra_links on SerializedBaseOperator? (since nobody should access these in the scheduler and webserver; the XCom mnechanism should be used instead)
  3. Make sure global links are also called and generated on execution time
  4. Restore get_link to only be expect BaseOperator subclasses; may need to tweak execution slightly to make sure it’s only called after a MappedOperator is unmapped into a BaseOperator

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One extra wrinkle here @uranusjr is that plugon-based global operator links would still possible work in the Webserver.

@kaxil
kaxil merged commit cfce573 into apache:mainAug 23, 2025
57 checks passed
@kaxil
kaxil deleted the remove-unmap-from-scheduler branch August 23, 2025 22:49
mangal-vairalkar pushed a commit to mangal-vairalkar/airflow that referenced this pull request Aug 30, 2025
Remove unnecessary unmap() functionality from server-side operators to
simplify scheduler architecture and eliminate synthetic operator creation.
Key changes:
- Remove unmap() method from MappedOperator class
- Update TaskInstance.fetch_handle_failure_context() to use original task directly
- Remove unmap() call from SerializedBaseOperator.get_extra_links()
- Update related tests to verify serialization without unmap functionality
The scheduler no longer needs to 'unmap' operators since:
- Callbacks are handled by DAG processor, not scheduler
- Email settings and fail-fast logic work with original task
- Extra links work consistently between regular and mapped operators
This eliminates the TODO comment about moving runtime unmap to task runner
and provides cleaner separation between scheduler and execution concerns.
Includes pre-commit formatting fixes applied by ruff and ruff-format.
bggwak pushed a commit to bggwak/airflow that referenced this pull request Sep 2, 2025
Remove unnecessary unmap() functionality from server-side operators to
simplify scheduler architecture and eliminate synthetic operator creation.
Key changes:
- Remove unmap() method from MappedOperator class
- Update TaskInstance.fetch_handle_failure_context() to use original task directly
- Remove unmap() call from SerializedBaseOperator.get_extra_links()
- Update related tests to verify serialization without unmap functionality
The scheduler no longer needs to 'unmap' operators since:
- Callbacks are handled by DAG processor, not scheduler
- Email settings and fail-fast logic work with original task
- Extra links work consistently between regular and mapped operators
This eliminates the TODO comment about moving runtime unmap to task runner
and provides cleaner separation between scheduler and execution concerns.
Includes pre-commit formatting fixes applied by ruff and ruff-format.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

No open projects

Development

Successfully merging this pull request may close these issues.

3 participants

@kaxil@ashb@uranusjr
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Remove unmap method from scheduler-side - #54816

Merged
kaxil merged 1 commit into
apache:mainfrom
astronomer:remove-unmap-from-scheduler
Aug 23, 2025
Merged

Remove unmap method from scheduler-side#54816
kaxil merged 1 commit into
apache:mainfrom
astronomer:remove-unmap-from-scheduler

Conversation

@kaxil

Copy link
Copy Markdown
Member

The scheduler-side MappedOperator and SerializedBaseOperator classes contained unmap() functionality that was creating unnecessary complexity and architectural confusion. The unmap() method was attempting to synthesize "real" operators from serialized data, but this is not needed for scheduler operations.

Scheduler doesn't execute callbacks - that's handled by the DAG processor. So simplifying the codebase.

This would also be helpful for #54569

Remove unnecessary unmap() functionality from server-side operators to
simplify scheduler architecture and eliminate synthetic operator creation.
Key changes:
- Remove unmap() method from MappedOperator class
- Update TaskInstance.fetch_handle_failure_context() to use original task directly
- Remove unmap() call from SerializedBaseOperator.get_extra_links()
- Update related tests to verify serialization without unmap functionality
The scheduler no longer needs to 'unmap' operators since:
- Callbacks are handled by DAG processor, not scheduler
- Email settings and fail-fast logic work with original task
- Extra links work consistently between regular and mapped operators
This eliminates the TODO comment about moving runtime unmap to task runner
and provides cleaner separation between scheduler and execution concerns.
Includes pre-commit formatting fixes applied by ruff and ruff-format.
Comment on lines -1312 to +1311
return link.get_link(self.unmap(None), ti_key=ti.key) # type: ignore[arg-type] # TODO: GH-52141 - BaseOperatorLink.get_link expects BaseOperator but receives SerializedBaseOperator
return link.get_link(self, ti_key=ti.key) # type: ignore[arg-type] # TODO: GH-52141 - BaseOperatorLink.get_link expects BaseOperator but receives SerializedBaseOperator

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I wonder if this should be kept. Would users expect get_link to be called against a MappedOperator? It may not have the same attributes as the underlying operator.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

models.MappedOperator also defines def get_extra_links -- so either is already broken or there should be no change with this on it 🤷

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

defget_extra_links(self, ti: TaskInstance, name: str) ->str|None:
"""
For an operator, gets the URLs that the ``extra_links`` entry points to.
:meta private:
:raise ValueError: The error message of a ValueError will be passed on through to
the fronted to show up as a tooltip on the disabled link.
:param ti: The TaskInstance for the URL being searched for.
:param name: The name of the link we're looking for the URL for. Should be
one of the options specified in ``extra_links``.
"""
link=self.operator_extra_link_dict.get(name) orself.global_operator_extra_link_dict.get(name)
ifnotlink:
returnNone
returnlink.get_link(self, ti_key=ti.key) # type: ignore[arg-type] # TODO: GH-52141 - BaseOperatorLink.get_link expects BaseOperator but receives MappedOperator

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With 3.0.0 get links aren't called in the scheduler or really the webserver anymore - we get the link in the execution side and store it in the xcom as an XComExtraLink (or something like that)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this only gets called for plugin registered global links.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually I think this was from a series of incorrect changes… get_link used to only accept BaseOperator before this change
#46613

You can see get_extra_links always calls unmap to get a BaseOperator.

After the PR above, get_extra_links was then incorrectly “restored” to pass in MappedOperator in #50238. This PR has not been a release yet.

I think removing unmap here is therefore wrong. It should be kept for get_extra_links for compatibility.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@uranusjr#46613 is released in 3.0.0 and #50238 in 3.0.1

get_link used to only accept BaseOperator before this change

How would that work with CustomOperators though! We don't serialize all attributes so extra_links with operator as argument will have limited attributes to work with for global op links

@uranusjruranusjrAug 27, 2025

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the thing was original designed we could get the original operator class from a dag bag… but yeah I guess all these no longer apply now.

Now that we always do get_link in the worker (#54816 (comment)), we can always get the original operator class (you need to unmap for execution anyway), so I guess what we need to do is

  1. This PR is OK, we don’t need unmap at scheduler side
  2. Not have extra_links and get_extra_links on SerializedBaseOperator? (since nobody should access these in the scheduler and webserver; the XCom mnechanism should be used instead)
  3. Make sure global links are also called and generated on execution time
  4. Restore get_link to only be expect BaseOperator subclasses; may need to tweak execution slightly to make sure it’s only called after a MappedOperator is unmapped into a BaseOperator

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One extra wrinkle here @uranusjr is that plugon-based global operator links would still possible work in the Webserver.

@kaxil
kaxil merged commit cfce573 into apache:mainAug 23, 2025
57 checks passed
@kaxil
kaxil deleted the remove-unmap-from-scheduler branch August 23, 2025 22:49
mangal-vairalkar pushed a commit to mangal-vairalkar/airflow that referenced this pull request Aug 30, 2025
Remove unnecessary unmap() functionality from server-side operators to
simplify scheduler architecture and eliminate synthetic operator creation.
Key changes:
- Remove unmap() method from MappedOperator class
- Update TaskInstance.fetch_handle_failure_context() to use original task directly
- Remove unmap() call from SerializedBaseOperator.get_extra_links()
- Update related tests to verify serialization without unmap functionality
The scheduler no longer needs to 'unmap' operators since:
- Callbacks are handled by DAG processor, not scheduler
- Email settings and fail-fast logic work with original task
- Extra links work consistently between regular and mapped operators
This eliminates the TODO comment about moving runtime unmap to task runner
and provides cleaner separation between scheduler and execution concerns.
Includes pre-commit formatting fixes applied by ruff and ruff-format.
bggwak pushed a commit to bggwak/airflow that referenced this pull request Sep 2, 2025
Remove unnecessary unmap() functionality from server-side operators to
simplify scheduler architecture and eliminate synthetic operator creation.
Key changes:
- Remove unmap() method from MappedOperator class
- Update TaskInstance.fetch_handle_failure_context() to use original task directly
- Remove unmap() call from SerializedBaseOperator.get_extra_links()
- Update related tests to verify serialization without unmap functionality
The scheduler no longer needs to 'unmap' operators since:
- Callbacks are handled by DAG processor, not scheduler
- Email settings and fail-fast logic work with original task
- Extra links work consistently between regular and mapped operators
This eliminates the TODO comment about moving runtime unmap to task runner
and provides cleaner separation between scheduler and execution concerns.
Includes pre-commit formatting fixes applied by ruff and ruff-format.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

No open projects

Development

Successfully merging this pull request may close these issues.

3 participants

@kaxil@ashb@uranusjr
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Remove unmap method from scheduler-side - #54816

Merged
kaxil merged 1 commit into
apache:mainfrom
astronomer:remove-unmap-from-scheduler
Aug 23, 2025
Merged

Remove unmap method from scheduler-side#54816
kaxil merged 1 commit into
apache:mainfrom
astronomer:remove-unmap-from-scheduler

Conversation

@kaxil

Copy link
Copy Markdown
Member

The scheduler-side MappedOperator and SerializedBaseOperator classes contained unmap() functionality that was creating unnecessary complexity and architectural confusion. The unmap() method was attempting to synthesize "real" operators from serialized data, but this is not needed for scheduler operations.

Scheduler doesn't execute callbacks - that's handled by the DAG processor. So simplifying the codebase.

This would also be helpful for #54569

Remove unnecessary unmap() functionality from server-side operators to
simplify scheduler architecture and eliminate synthetic operator creation.
Key changes:
- Remove unmap() method from MappedOperator class
- Update TaskInstance.fetch_handle_failure_context() to use original task directly
- Remove unmap() call from SerializedBaseOperator.get_extra_links()
- Update related tests to verify serialization without unmap functionality
The scheduler no longer needs to 'unmap' operators since:
- Callbacks are handled by DAG processor, not scheduler
- Email settings and fail-fast logic work with original task
- Extra links work consistently between regular and mapped operators
This eliminates the TODO comment about moving runtime unmap to task runner
and provides cleaner separation between scheduler and execution concerns.
Includes pre-commit formatting fixes applied by ruff and ruff-format.
Comment on lines -1312 to +1311
return link.get_link(self.unmap(None), ti_key=ti.key) # type: ignore[arg-type] # TODO: GH-52141 - BaseOperatorLink.get_link expects BaseOperator but receives SerializedBaseOperator
return link.get_link(self, ti_key=ti.key) # type: ignore[arg-type] # TODO: GH-52141 - BaseOperatorLink.get_link expects BaseOperator but receives SerializedBaseOperator

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I wonder if this should be kept. Would users expect get_link to be called against a MappedOperator? It may not have the same attributes as the underlying operator.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

models.MappedOperator also defines def get_extra_links -- so either is already broken or there should be no change with this on it 🤷

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

defget_extra_links(self, ti: TaskInstance, name: str) ->str|None:
"""
For an operator, gets the URLs that the ``extra_links`` entry points to.
:meta private:
:raise ValueError: The error message of a ValueError will be passed on through to
the fronted to show up as a tooltip on the disabled link.
:param ti: The TaskInstance for the URL being searched for.
:param name: The name of the link we're looking for the URL for. Should be
one of the options specified in ``extra_links``.
"""
link=self.operator_extra_link_dict.get(name) orself.global_operator_extra_link_dict.get(name)
ifnotlink:
returnNone
returnlink.get_link(self, ti_key=ti.key) # type: ignore[arg-type] # TODO: GH-52141 - BaseOperatorLink.get_link expects BaseOperator but receives MappedOperator

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With 3.0.0 get links aren't called in the scheduler or really the webserver anymore - we get the link in the execution side and store it in the xcom as an XComExtraLink (or something like that)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this only gets called for plugin registered global links.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually I think this was from a series of incorrect changes… get_link used to only accept BaseOperator before this change
#46613

You can see get_extra_links always calls unmap to get a BaseOperator.

After the PR above, get_extra_links was then incorrectly “restored” to pass in MappedOperator in #50238. This PR has not been a release yet.

I think removing unmap here is therefore wrong. It should be kept for get_extra_links for compatibility.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@uranusjr#46613 is released in 3.0.0 and #50238 in 3.0.1

get_link used to only accept BaseOperator before this change

How would that work with CustomOperators though! We don't serialize all attributes so extra_links with operator as argument will have limited attributes to work with for global op links

@uranusjruranusjrAug 27, 2025

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the thing was original designed we could get the original operator class from a dag bag… but yeah I guess all these no longer apply now.

Now that we always do get_link in the worker (#54816 (comment)), we can always get the original operator class (you need to unmap for execution anyway), so I guess what we need to do is

  1. This PR is OK, we don’t need unmap at scheduler side
  2. Not have extra_links and get_extra_links on SerializedBaseOperator? (since nobody should access these in the scheduler and webserver; the XCom mnechanism should be used instead)
  3. Make sure global links are also called and generated on execution time
  4. Restore get_link to only be expect BaseOperator subclasses; may need to tweak execution slightly to make sure it’s only called after a MappedOperator is unmapped into a BaseOperator

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One extra wrinkle here @uranusjr is that plugon-based global operator links would still possible work in the Webserver.

@kaxil
kaxil merged commit cfce573 into apache:mainAug 23, 2025
57 checks passed
@kaxil
kaxil deleted the remove-unmap-from-scheduler branch August 23, 2025 22:49
mangal-vairalkar pushed a commit to mangal-vairalkar/airflow that referenced this pull request Aug 30, 2025
Remove unnecessary unmap() functionality from server-side operators to
simplify scheduler architecture and eliminate synthetic operator creation.
Key changes:
- Remove unmap() method from MappedOperator class
- Update TaskInstance.fetch_handle_failure_context() to use original task directly
- Remove unmap() call from SerializedBaseOperator.get_extra_links()
- Update related tests to verify serialization without unmap functionality
The scheduler no longer needs to 'unmap' operators since:
- Callbacks are handled by DAG processor, not scheduler
- Email settings and fail-fast logic work with original task
- Extra links work consistently between regular and mapped operators
This eliminates the TODO comment about moving runtime unmap to task runner
and provides cleaner separation between scheduler and execution concerns.
Includes pre-commit formatting fixes applied by ruff and ruff-format.
bggwak pushed a commit to bggwak/airflow that referenced this pull request Sep 2, 2025
Remove unnecessary unmap() functionality from server-side operators to
simplify scheduler architecture and eliminate synthetic operator creation.
Key changes:
- Remove unmap() method from MappedOperator class
- Update TaskInstance.fetch_handle_failure_context() to use original task directly
- Remove unmap() call from SerializedBaseOperator.get_extra_links()
- Update related tests to verify serialization without unmap functionality
The scheduler no longer needs to 'unmap' operators since:
- Callbacks are handled by DAG processor, not scheduler
- Email settings and fail-fast logic work with original task
- Extra links work consistently between regular and mapped operators
This eliminates the TODO comment about moving runtime unmap to task runner
and provides cleaner separation between scheduler and execution concerns.
Includes pre-commit formatting fixes applied by ruff and ruff-format.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

No open projects

Development

Successfully merging this pull request may close these issues.

3 participants

@kaxil@ashb@uranusjr
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Remove unmap method from scheduler-side - #54816

Merged
kaxil merged 1 commit into
apache:mainfrom
astronomer:remove-unmap-from-scheduler
Aug 23, 2025
Merged

Remove unmap method from scheduler-side#54816
kaxil merged 1 commit into
apache:mainfrom
astronomer:remove-unmap-from-scheduler

Conversation

@kaxil

Copy link
Copy Markdown
Member

The scheduler-side MappedOperator and SerializedBaseOperator classes contained unmap() functionality that was creating unnecessary complexity and architectural confusion. The unmap() method was attempting to synthesize "real" operators from serialized data, but this is not needed for scheduler operations.

Scheduler doesn't execute callbacks - that's handled by the DAG processor. So simplifying the codebase.

This would also be helpful for #54569

Remove unnecessary unmap() functionality from server-side operators to
simplify scheduler architecture and eliminate synthetic operator creation.
Key changes:
- Remove unmap() method from MappedOperator class
- Update TaskInstance.fetch_handle_failure_context() to use original task directly
- Remove unmap() call from SerializedBaseOperator.get_extra_links()
- Update related tests to verify serialization without unmap functionality
The scheduler no longer needs to 'unmap' operators since:
- Callbacks are handled by DAG processor, not scheduler
- Email settings and fail-fast logic work with original task
- Extra links work consistently between regular and mapped operators
This eliminates the TODO comment about moving runtime unmap to task runner
and provides cleaner separation between scheduler and execution concerns.
Includes pre-commit formatting fixes applied by ruff and ruff-format.
Comment on lines -1312 to +1311
return link.get_link(self.unmap(None), ti_key=ti.key) # type: ignore[arg-type] # TODO: GH-52141 - BaseOperatorLink.get_link expects BaseOperator but receives SerializedBaseOperator
return link.get_link(self, ti_key=ti.key) # type: ignore[arg-type] # TODO: GH-52141 - BaseOperatorLink.get_link expects BaseOperator but receives SerializedBaseOperator

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I wonder if this should be kept. Would users expect get_link to be called against a MappedOperator? It may not have the same attributes as the underlying operator.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

models.MappedOperator also defines def get_extra_links -- so either is already broken or there should be no change with this on it 🤷

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

defget_extra_links(self, ti: TaskInstance, name: str) ->str|None:
"""
For an operator, gets the URLs that the ``extra_links`` entry points to.
:meta private:
:raise ValueError: The error message of a ValueError will be passed on through to
the fronted to show up as a tooltip on the disabled link.
:param ti: The TaskInstance for the URL being searched for.
:param name: The name of the link we're looking for the URL for. Should be
one of the options specified in ``extra_links``.
"""
link=self.operator_extra_link_dict.get(name) orself.global_operator_extra_link_dict.get(name)
ifnotlink:
returnNone
returnlink.get_link(self, ti_key=ti.key) # type: ignore[arg-type] # TODO: GH-52141 - BaseOperatorLink.get_link expects BaseOperator but receives MappedOperator

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With 3.0.0 get links aren't called in the scheduler or really the webserver anymore - we get the link in the execution side and store it in the xcom as an XComExtraLink (or something like that)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this only gets called for plugin registered global links.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually I think this was from a series of incorrect changes… get_link used to only accept BaseOperator before this change
#46613

You can see get_extra_links always calls unmap to get a BaseOperator.

After the PR above, get_extra_links was then incorrectly “restored” to pass in MappedOperator in #50238. This PR has not been a release yet.

I think removing unmap here is therefore wrong. It should be kept for get_extra_links for compatibility.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@uranusjr#46613 is released in 3.0.0 and #50238 in 3.0.1

get_link used to only accept BaseOperator before this change

How would that work with CustomOperators though! We don't serialize all attributes so extra_links with operator as argument will have limited attributes to work with for global op links

@uranusjruranusjrAug 27, 2025

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the thing was original designed we could get the original operator class from a dag bag… but yeah I guess all these no longer apply now.

Now that we always do get_link in the worker (#54816 (comment)), we can always get the original operator class (you need to unmap for execution anyway), so I guess what we need to do is

  1. This PR is OK, we don’t need unmap at scheduler side
  2. Not have extra_links and get_extra_links on SerializedBaseOperator? (since nobody should access these in the scheduler and webserver; the XCom mnechanism should be used instead)
  3. Make sure global links are also called and generated on execution time
  4. Restore get_link to only be expect BaseOperator subclasses; may need to tweak execution slightly to make sure it’s only called after a MappedOperator is unmapped into a BaseOperator

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One extra wrinkle here @uranusjr is that plugon-based global operator links would still possible work in the Webserver.

@kaxil
kaxil merged commit cfce573 into apache:mainAug 23, 2025
57 checks passed
@kaxil
kaxil deleted the remove-unmap-from-scheduler branch August 23, 2025 22:49
mangal-vairalkar pushed a commit to mangal-vairalkar/airflow that referenced this pull request Aug 30, 2025
Remove unnecessary unmap() functionality from server-side operators to
simplify scheduler architecture and eliminate synthetic operator creation.
Key changes:
- Remove unmap() method from MappedOperator class
- Update TaskInstance.fetch_handle_failure_context() to use original task directly
- Remove unmap() call from SerializedBaseOperator.get_extra_links()
- Update related tests to verify serialization without unmap functionality
The scheduler no longer needs to 'unmap' operators since:
- Callbacks are handled by DAG processor, not scheduler
- Email settings and fail-fast logic work with original task
- Extra links work consistently between regular and mapped operators
This eliminates the TODO comment about moving runtime unmap to task runner
and provides cleaner separation between scheduler and execution concerns.
Includes pre-commit formatting fixes applied by ruff and ruff-format.
bggwak pushed a commit to bggwak/airflow that referenced this pull request Sep 2, 2025
Remove unnecessary unmap() functionality from server-side operators to
simplify scheduler architecture and eliminate synthetic operator creation.
Key changes:
- Remove unmap() method from MappedOperator class
- Update TaskInstance.fetch_handle_failure_context() to use original task directly
- Remove unmap() call from SerializedBaseOperator.get_extra_links()
- Update related tests to verify serialization without unmap functionality
The scheduler no longer needs to 'unmap' operators since:
- Callbacks are handled by DAG processor, not scheduler
- Email settings and fail-fast logic work with original task
- Extra links work consistently between regular and mapped operators
This eliminates the TODO comment about moving runtime unmap to task runner
and provides cleaner separation between scheduler and execution concerns.
Includes pre-commit formatting fixes applied by ruff and ruff-format.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

No open projects

Development

Successfully merging this pull request may close these issues.

3 participants

@kaxil@ashb@uranusjr
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Remove unmap method from scheduler-side - #54816

Merged
kaxil merged 1 commit into
apache:mainfrom
astronomer:remove-unmap-from-scheduler
Aug 23, 2025
Merged

Remove unmap method from scheduler-side#54816
kaxil merged 1 commit into
apache:mainfrom
astronomer:remove-unmap-from-scheduler

Conversation

@kaxil

Copy link
Copy Markdown
Member

The scheduler-side MappedOperator and SerializedBaseOperator classes contained unmap() functionality that was creating unnecessary complexity and architectural confusion. The unmap() method was attempting to synthesize "real" operators from serialized data, but this is not needed for scheduler operations.

Scheduler doesn't execute callbacks - that's handled by the DAG processor. So simplifying the codebase.

This would also be helpful for #54569

Remove unnecessary unmap() functionality from server-side operators to
simplify scheduler architecture and eliminate synthetic operator creation.
Key changes:
- Remove unmap() method from MappedOperator class
- Update TaskInstance.fetch_handle_failure_context() to use original task directly
- Remove unmap() call from SerializedBaseOperator.get_extra_links()
- Update related tests to verify serialization without unmap functionality
The scheduler no longer needs to 'unmap' operators since:
- Callbacks are handled by DAG processor, not scheduler
- Email settings and fail-fast logic work with original task
- Extra links work consistently between regular and mapped operators
This eliminates the TODO comment about moving runtime unmap to task runner
and provides cleaner separation between scheduler and execution concerns.
Includes pre-commit formatting fixes applied by ruff and ruff-format.
Comment on lines -1312 to +1311
return link.get_link(self.unmap(None), ti_key=ti.key) # type: ignore[arg-type] # TODO: GH-52141 - BaseOperatorLink.get_link expects BaseOperator but receives SerializedBaseOperator
return link.get_link(self, ti_key=ti.key) # type: ignore[arg-type] # TODO: GH-52141 - BaseOperatorLink.get_link expects BaseOperator but receives SerializedBaseOperator

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I wonder if this should be kept. Would users expect get_link to be called against a MappedOperator? It may not have the same attributes as the underlying operator.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

models.MappedOperator also defines def get_extra_links -- so either is already broken or there should be no change with this on it 🤷

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

defget_extra_links(self, ti: TaskInstance, name: str) ->str|None:
"""
For an operator, gets the URLs that the ``extra_links`` entry points to.
:meta private:
:raise ValueError: The error message of a ValueError will be passed on through to
the fronted to show up as a tooltip on the disabled link.
:param ti: The TaskInstance for the URL being searched for.
:param name: The name of the link we're looking for the URL for. Should be
one of the options specified in ``extra_links``.
"""
link=self.operator_extra_link_dict.get(name) orself.global_operator_extra_link_dict.get(name)
ifnotlink:
returnNone
returnlink.get_link(self, ti_key=ti.key) # type: ignore[arg-type] # TODO: GH-52141 - BaseOperatorLink.get_link expects BaseOperator but receives MappedOperator

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With 3.0.0 get links aren't called in the scheduler or really the webserver anymore - we get the link in the execution side and store it in the xcom as an XComExtraLink (or something like that)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this only gets called for plugin registered global links.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually I think this was from a series of incorrect changes… get_link used to only accept BaseOperator before this change
#46613

You can see get_extra_links always calls unmap to get a BaseOperator.

After the PR above, get_extra_links was then incorrectly “restored” to pass in MappedOperator in #50238. This PR has not been a release yet.

I think removing unmap here is therefore wrong. It should be kept for get_extra_links for compatibility.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@uranusjr#46613 is released in 3.0.0 and #50238 in 3.0.1

get_link used to only accept BaseOperator before this change

How would that work with CustomOperators though! We don't serialize all attributes so extra_links with operator as argument will have limited attributes to work with for global op links

@uranusjruranusjrAug 27, 2025

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the thing was original designed we could get the original operator class from a dag bag… but yeah I guess all these no longer apply now.

Now that we always do get_link in the worker (#54816 (comment)), we can always get the original operator class (you need to unmap for execution anyway), so I guess what we need to do is

  1. This PR is OK, we don’t need unmap at scheduler side
  2. Not have extra_links and get_extra_links on SerializedBaseOperator? (since nobody should access these in the scheduler and webserver; the XCom mnechanism should be used instead)
  3. Make sure global links are also called and generated on execution time
  4. Restore get_link to only be expect BaseOperator subclasses; may need to tweak execution slightly to make sure it’s only called after a MappedOperator is unmapped into a BaseOperator

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One extra wrinkle here @uranusjr is that plugon-based global operator links would still possible work in the Webserver.

@kaxil
kaxil merged commit cfce573 into apache:mainAug 23, 2025
57 checks passed
@kaxil
kaxil deleted the remove-unmap-from-scheduler branch August 23, 2025 22:49
mangal-vairalkar pushed a commit to mangal-vairalkar/airflow that referenced this pull request Aug 30, 2025
Remove unnecessary unmap() functionality from server-side operators to
simplify scheduler architecture and eliminate synthetic operator creation.
Key changes:
- Remove unmap() method from MappedOperator class
- Update TaskInstance.fetch_handle_failure_context() to use original task directly
- Remove unmap() call from SerializedBaseOperator.get_extra_links()
- Update related tests to verify serialization without unmap functionality
The scheduler no longer needs to 'unmap' operators since:
- Callbacks are handled by DAG processor, not scheduler
- Email settings and fail-fast logic work with original task
- Extra links work consistently between regular and mapped operators
This eliminates the TODO comment about moving runtime unmap to task runner
and provides cleaner separation between scheduler and execution concerns.
Includes pre-commit formatting fixes applied by ruff and ruff-format.
bggwak pushed a commit to bggwak/airflow that referenced this pull request Sep 2, 2025
Remove unnecessary unmap() functionality from server-side operators to
simplify scheduler architecture and eliminate synthetic operator creation.
Key changes:
- Remove unmap() method from MappedOperator class
- Update TaskInstance.fetch_handle_failure_context() to use original task directly
- Remove unmap() call from SerializedBaseOperator.get_extra_links()
- Update related tests to verify serialization without unmap functionality
The scheduler no longer needs to 'unmap' operators since:
- Callbacks are handled by DAG processor, not scheduler
- Email settings and fail-fast logic work with original task
- Extra links work consistently between regular and mapped operators
This eliminates the TODO comment about moving runtime unmap to task runner
and provides cleaner separation between scheduler and execution concerns.
Includes pre-commit formatting fixes applied by ruff and ruff-format.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

No open projects

Development

Successfully merging this pull request may close these issues.

3 participants

@kaxil@ashb@uranusjr
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Remove unmap method from scheduler-side - #54816

Merged
kaxil merged 1 commit into
apache:mainfrom
astronomer:remove-unmap-from-scheduler
Aug 23, 2025
Merged

Remove unmap method from scheduler-side#54816
kaxil merged 1 commit into
apache:mainfrom
astronomer:remove-unmap-from-scheduler

Conversation

@kaxil

Copy link
Copy Markdown
Member

The scheduler-side MappedOperator and SerializedBaseOperator classes contained unmap() functionality that was creating unnecessary complexity and architectural confusion. The unmap() method was attempting to synthesize "real" operators from serialized data, but this is not needed for scheduler operations.

Scheduler doesn't execute callbacks - that's handled by the DAG processor. So simplifying the codebase.

This would also be helpful for #54569

Remove unnecessary unmap() functionality from server-side operators to
simplify scheduler architecture and eliminate synthetic operator creation.
Key changes:
- Remove unmap() method from MappedOperator class
- Update TaskInstance.fetch_handle_failure_context() to use original task directly
- Remove unmap() call from SerializedBaseOperator.get_extra_links()
- Update related tests to verify serialization without unmap functionality
The scheduler no longer needs to 'unmap' operators since:
- Callbacks are handled by DAG processor, not scheduler
- Email settings and fail-fast logic work with original task
- Extra links work consistently between regular and mapped operators
This eliminates the TODO comment about moving runtime unmap to task runner
and provides cleaner separation between scheduler and execution concerns.
Includes pre-commit formatting fixes applied by ruff and ruff-format.
Comment on lines -1312 to +1311
return link.get_link(self.unmap(None), ti_key=ti.key) # type: ignore[arg-type] # TODO: GH-52141 - BaseOperatorLink.get_link expects BaseOperator but receives SerializedBaseOperator
return link.get_link(self, ti_key=ti.key) # type: ignore[arg-type] # TODO: GH-52141 - BaseOperatorLink.get_link expects BaseOperator but receives SerializedBaseOperator

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I wonder if this should be kept. Would users expect get_link to be called against a MappedOperator? It may not have the same attributes as the underlying operator.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

models.MappedOperator also defines def get_extra_links -- so either is already broken or there should be no change with this on it 🤷

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

defget_extra_links(self, ti: TaskInstance, name: str) ->str|None:
"""
For an operator, gets the URLs that the ``extra_links`` entry points to.
:meta private:
:raise ValueError: The error message of a ValueError will be passed on through to
the fronted to show up as a tooltip on the disabled link.
:param ti: The TaskInstance for the URL being searched for.
:param name: The name of the link we're looking for the URL for. Should be
one of the options specified in ``extra_links``.
"""
link=self.operator_extra_link_dict.get(name) orself.global_operator_extra_link_dict.get(name)
ifnotlink:
returnNone
returnlink.get_link(self, ti_key=ti.key) # type: ignore[arg-type] # TODO: GH-52141 - BaseOperatorLink.get_link expects BaseOperator but receives MappedOperator

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With 3.0.0 get links aren't called in the scheduler or really the webserver anymore - we get the link in the execution side and store it in the xcom as an XComExtraLink (or something like that)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this only gets called for plugin registered global links.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually I think this was from a series of incorrect changes… get_link used to only accept BaseOperator before this change
#46613

You can see get_extra_links always calls unmap to get a BaseOperator.

After the PR above, get_extra_links was then incorrectly “restored” to pass in MappedOperator in #50238. This PR has not been a release yet.

I think removing unmap here is therefore wrong. It should be kept for get_extra_links for compatibility.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@uranusjr#46613 is released in 3.0.0 and #50238 in 3.0.1

get_link used to only accept BaseOperator before this change

How would that work with CustomOperators though! We don't serialize all attributes so extra_links with operator as argument will have limited attributes to work with for global op links

@uranusjruranusjrAug 27, 2025

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the thing was original designed we could get the original operator class from a dag bag… but yeah I guess all these no longer apply now.

Now that we always do get_link in the worker (#54816 (comment)), we can always get the original operator class (you need to unmap for execution anyway), so I guess what we need to do is

  1. This PR is OK, we don’t need unmap at scheduler side
  2. Not have extra_links and get_extra_links on SerializedBaseOperator? (since nobody should access these in the scheduler and webserver; the XCom mnechanism should be used instead)
  3. Make sure global links are also called and generated on execution time
  4. Restore get_link to only be expect BaseOperator subclasses; may need to tweak execution slightly to make sure it’s only called after a MappedOperator is unmapped into a BaseOperator

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One extra wrinkle here @uranusjr is that plugon-based global operator links would still possible work in the Webserver.

@kaxil
kaxil merged commit cfce573 into apache:mainAug 23, 2025
57 checks passed
@kaxil
kaxil deleted the remove-unmap-from-scheduler branch August 23, 2025 22:49
mangal-vairalkar pushed a commit to mangal-vairalkar/airflow that referenced this pull request Aug 30, 2025
Remove unnecessary unmap() functionality from server-side operators to
simplify scheduler architecture and eliminate synthetic operator creation.
Key changes:
- Remove unmap() method from MappedOperator class
- Update TaskInstance.fetch_handle_failure_context() to use original task directly
- Remove unmap() call from SerializedBaseOperator.get_extra_links()
- Update related tests to verify serialization without unmap functionality
The scheduler no longer needs to 'unmap' operators since:
- Callbacks are handled by DAG processor, not scheduler
- Email settings and fail-fast logic work with original task
- Extra links work consistently between regular and mapped operators
This eliminates the TODO comment about moving runtime unmap to task runner
and provides cleaner separation between scheduler and execution concerns.
Includes pre-commit formatting fixes applied by ruff and ruff-format.
bggwak pushed a commit to bggwak/airflow that referenced this pull request Sep 2, 2025
Remove unnecessary unmap() functionality from server-side operators to
simplify scheduler architecture and eliminate synthetic operator creation.
Key changes:
- Remove unmap() method from MappedOperator class
- Update TaskInstance.fetch_handle_failure_context() to use original task directly
- Remove unmap() call from SerializedBaseOperator.get_extra_links()
- Update related tests to verify serialization without unmap functionality
The scheduler no longer needs to 'unmap' operators since:
- Callbacks are handled by DAG processor, not scheduler
- Email settings and fail-fast logic work with original task
- Extra links work consistently between regular and mapped operators
This eliminates the TODO comment about moving runtime unmap to task runner
and provides cleaner separation between scheduler and execution concerns.
Includes pre-commit formatting fixes applied by ruff and ruff-format.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

No open projects

Development

Successfully merging this pull request may close these issues.

3 participants

@kaxil@ashb@uranusjr
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Remove unmap method from scheduler-side - #54816

Merged
kaxil merged 1 commit into
apache:mainfrom
astronomer:remove-unmap-from-scheduler
Aug 23, 2025
Merged

Remove unmap method from scheduler-side#54816
kaxil merged 1 commit into
apache:mainfrom
astronomer:remove-unmap-from-scheduler

Conversation

@kaxil

Copy link
Copy Markdown
Member

The scheduler-side MappedOperator and SerializedBaseOperator classes contained unmap() functionality that was creating unnecessary complexity and architectural confusion. The unmap() method was attempting to synthesize "real" operators from serialized data, but this is not needed for scheduler operations.

Scheduler doesn't execute callbacks - that's handled by the DAG processor. So simplifying the codebase.

This would also be helpful for #54569

Remove unnecessary unmap() functionality from server-side operators to
simplify scheduler architecture and eliminate synthetic operator creation.
Key changes:
- Remove unmap() method from MappedOperator class
- Update TaskInstance.fetch_handle_failure_context() to use original task directly
- Remove unmap() call from SerializedBaseOperator.get_extra_links()
- Update related tests to verify serialization without unmap functionality
The scheduler no longer needs to 'unmap' operators since:
- Callbacks are handled by DAG processor, not scheduler
- Email settings and fail-fast logic work with original task
- Extra links work consistently between regular and mapped operators
This eliminates the TODO comment about moving runtime unmap to task runner
and provides cleaner separation between scheduler and execution concerns.
Includes pre-commit formatting fixes applied by ruff and ruff-format.
Comment on lines -1312 to +1311
return link.get_link(self.unmap(None), ti_key=ti.key) # type: ignore[arg-type] # TODO: GH-52141 - BaseOperatorLink.get_link expects BaseOperator but receives SerializedBaseOperator
return link.get_link(self, ti_key=ti.key) # type: ignore[arg-type] # TODO: GH-52141 - BaseOperatorLink.get_link expects BaseOperator but receives SerializedBaseOperator

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I wonder if this should be kept. Would users expect get_link to be called against a MappedOperator? It may not have the same attributes as the underlying operator.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

models.MappedOperator also defines def get_extra_links -- so either is already broken or there should be no change with this on it 🤷

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

defget_extra_links(self, ti: TaskInstance, name: str) ->str|None:
"""
For an operator, gets the URLs that the ``extra_links`` entry points to.
:meta private:
:raise ValueError: The error message of a ValueError will be passed on through to
the fronted to show up as a tooltip on the disabled link.
:param ti: The TaskInstance for the URL being searched for.
:param name: The name of the link we're looking for the URL for. Should be
one of the options specified in ``extra_links``.
"""
link=self.operator_extra_link_dict.get(name) orself.global_operator_extra_link_dict.get(name)
ifnotlink:
returnNone
returnlink.get_link(self, ti_key=ti.key) # type: ignore[arg-type] # TODO: GH-52141 - BaseOperatorLink.get_link expects BaseOperator but receives MappedOperator

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With 3.0.0 get links aren't called in the scheduler or really the webserver anymore - we get the link in the execution side and store it in the xcom as an XComExtraLink (or something like that)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this only gets called for plugin registered global links.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually I think this was from a series of incorrect changes… get_link used to only accept BaseOperator before this change
#46613

You can see get_extra_links always calls unmap to get a BaseOperator.

After the PR above, get_extra_links was then incorrectly “restored” to pass in MappedOperator in #50238. This PR has not been a release yet.

I think removing unmap here is therefore wrong. It should be kept for get_extra_links for compatibility.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@uranusjr#46613 is released in 3.0.0 and #50238 in 3.0.1

get_link used to only accept BaseOperator before this change

How would that work with CustomOperators though! We don't serialize all attributes so extra_links with operator as argument will have limited attributes to work with for global op links

@uranusjruranusjrAug 27, 2025

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the thing was original designed we could get the original operator class from a dag bag… but yeah I guess all these no longer apply now.

Now that we always do get_link in the worker (#54816 (comment)), we can always get the original operator class (you need to unmap for execution anyway), so I guess what we need to do is

  1. This PR is OK, we don’t need unmap at scheduler side
  2. Not have extra_links and get_extra_links on SerializedBaseOperator? (since nobody should access these in the scheduler and webserver; the XCom mnechanism should be used instead)
  3. Make sure global links are also called and generated on execution time
  4. Restore get_link to only be expect BaseOperator subclasses; may need to tweak execution slightly to make sure it’s only called after a MappedOperator is unmapped into a BaseOperator

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One extra wrinkle here @uranusjr is that plugon-based global operator links would still possible work in the Webserver.

@kaxil
kaxil merged commit cfce573 into apache:mainAug 23, 2025
57 checks passed
@kaxil
kaxil deleted the remove-unmap-from-scheduler branch August 23, 2025 22:49
mangal-vairalkar pushed a commit to mangal-vairalkar/airflow that referenced this pull request Aug 30, 2025
Remove unnecessary unmap() functionality from server-side operators to
simplify scheduler architecture and eliminate synthetic operator creation.
Key changes:
- Remove unmap() method from MappedOperator class
- Update TaskInstance.fetch_handle_failure_context() to use original task directly
- Remove unmap() call from SerializedBaseOperator.get_extra_links()
- Update related tests to verify serialization without unmap functionality
The scheduler no longer needs to 'unmap' operators since:
- Callbacks are handled by DAG processor, not scheduler
- Email settings and fail-fast logic work with original task
- Extra links work consistently between regular and mapped operators
This eliminates the TODO comment about moving runtime unmap to task runner
and provides cleaner separation between scheduler and execution concerns.
Includes pre-commit formatting fixes applied by ruff and ruff-format.
bggwak pushed a commit to bggwak/airflow that referenced this pull request Sep 2, 2025
Remove unnecessary unmap() functionality from server-side operators to
simplify scheduler architecture and eliminate synthetic operator creation.
Key changes:
- Remove unmap() method from MappedOperator class
- Update TaskInstance.fetch_handle_failure_context() to use original task directly
- Remove unmap() call from SerializedBaseOperator.get_extra_links()
- Update related tests to verify serialization without unmap functionality
The scheduler no longer needs to 'unmap' operators since:
- Callbacks are handled by DAG processor, not scheduler
- Email settings and fail-fast logic work with original task
- Extra links work consistently between regular and mapped operators
This eliminates the TODO comment about moving runtime unmap to task runner
and provides cleaner separation between scheduler and execution concerns.
Includes pre-commit formatting fixes applied by ruff and ruff-format.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

No open projects

Development

Successfully merging this pull request may close these issues.

3 participants

@kaxil@ashb@uranusjr
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Remove unmap method from scheduler-side - #54816

Merged
kaxil merged 1 commit into
apache:mainfrom
astronomer:remove-unmap-from-scheduler
Aug 23, 2025
Merged

Remove unmap method from scheduler-side#54816
kaxil merged 1 commit into
apache:mainfrom
astronomer:remove-unmap-from-scheduler

Conversation

@kaxil

Copy link
Copy Markdown
Member

The scheduler-side MappedOperator and SerializedBaseOperator classes contained unmap() functionality that was creating unnecessary complexity and architectural confusion. The unmap() method was attempting to synthesize "real" operators from serialized data, but this is not needed for scheduler operations.

Scheduler doesn't execute callbacks - that's handled by the DAG processor. So simplifying the codebase.

This would also be helpful for #54569

Remove unnecessary unmap() functionality from server-side operators to
simplify scheduler architecture and eliminate synthetic operator creation.
Key changes:
- Remove unmap() method from MappedOperator class
- Update TaskInstance.fetch_handle_failure_context() to use original task directly
- Remove unmap() call from SerializedBaseOperator.get_extra_links()
- Update related tests to verify serialization without unmap functionality
The scheduler no longer needs to 'unmap' operators since:
- Callbacks are handled by DAG processor, not scheduler
- Email settings and fail-fast logic work with original task
- Extra links work consistently between regular and mapped operators
This eliminates the TODO comment about moving runtime unmap to task runner
and provides cleaner separation between scheduler and execution concerns.
Includes pre-commit formatting fixes applied by ruff and ruff-format.
Comment on lines -1312 to +1311
return link.get_link(self.unmap(None), ti_key=ti.key) # type: ignore[arg-type] # TODO: GH-52141 - BaseOperatorLink.get_link expects BaseOperator but receives SerializedBaseOperator
return link.get_link(self, ti_key=ti.key) # type: ignore[arg-type] # TODO: GH-52141 - BaseOperatorLink.get_link expects BaseOperator but receives SerializedBaseOperator

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I wonder if this should be kept. Would users expect get_link to be called against a MappedOperator? It may not have the same attributes as the underlying operator.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

models.MappedOperator also defines def get_extra_links -- so either is already broken or there should be no change with this on it 🤷

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

defget_extra_links(self, ti: TaskInstance, name: str) ->str|None:
"""
For an operator, gets the URLs that the ``extra_links`` entry points to.
:meta private:
:raise ValueError: The error message of a ValueError will be passed on through to
the fronted to show up as a tooltip on the disabled link.
:param ti: The TaskInstance for the URL being searched for.
:param name: The name of the link we're looking for the URL for. Should be
one of the options specified in ``extra_links``.
"""
link=self.operator_extra_link_dict.get(name) orself.global_operator_extra_link_dict.get(name)
ifnotlink:
returnNone
returnlink.get_link(self, ti_key=ti.key) # type: ignore[arg-type] # TODO: GH-52141 - BaseOperatorLink.get_link expects BaseOperator but receives MappedOperator

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With 3.0.0 get links aren't called in the scheduler or really the webserver anymore - we get the link in the execution side and store it in the xcom as an XComExtraLink (or something like that)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this only gets called for plugin registered global links.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually I think this was from a series of incorrect changes… get_link used to only accept BaseOperator before this change
#46613

You can see get_extra_links always calls unmap to get a BaseOperator.

After the PR above, get_extra_links was then incorrectly “restored” to pass in MappedOperator in #50238. This PR has not been a release yet.

I think removing unmap here is therefore wrong. It should be kept for get_extra_links for compatibility.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@uranusjr#46613 is released in 3.0.0 and #50238 in 3.0.1

get_link used to only accept BaseOperator before this change

How would that work with CustomOperators though! We don't serialize all attributes so extra_links with operator as argument will have limited attributes to work with for global op links

@uranusjruranusjrAug 27, 2025

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the thing was original designed we could get the original operator class from a dag bag… but yeah I guess all these no longer apply now.

Now that we always do get_link in the worker (#54816 (comment)), we can always get the original operator class (you need to unmap for execution anyway), so I guess what we need to do is

  1. This PR is OK, we don’t need unmap at scheduler side
  2. Not have extra_links and get_extra_links on SerializedBaseOperator? (since nobody should access these in the scheduler and webserver; the XCom mnechanism should be used instead)
  3. Make sure global links are also called and generated on execution time
  4. Restore get_link to only be expect BaseOperator subclasses; may need to tweak execution slightly to make sure it’s only called after a MappedOperator is unmapped into a BaseOperator

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One extra wrinkle here @uranusjr is that plugon-based global operator links would still possible work in the Webserver.

@kaxil
kaxil merged commit cfce573 into apache:mainAug 23, 2025
57 checks passed
@kaxil
kaxil deleted the remove-unmap-from-scheduler branch August 23, 2025 22:49
mangal-vairalkar pushed a commit to mangal-vairalkar/airflow that referenced this pull request Aug 30, 2025
Remove unnecessary unmap() functionality from server-side operators to
simplify scheduler architecture and eliminate synthetic operator creation.
Key changes:
- Remove unmap() method from MappedOperator class
- Update TaskInstance.fetch_handle_failure_context() to use original task directly
- Remove unmap() call from SerializedBaseOperator.get_extra_links()
- Update related tests to verify serialization without unmap functionality
The scheduler no longer needs to 'unmap' operators since:
- Callbacks are handled by DAG processor, not scheduler
- Email settings and fail-fast logic work with original task
- Extra links work consistently between regular and mapped operators
This eliminates the TODO comment about moving runtime unmap to task runner
and provides cleaner separation between scheduler and execution concerns.
Includes pre-commit formatting fixes applied by ruff and ruff-format.
bggwak pushed a commit to bggwak/airflow that referenced this pull request Sep 2, 2025
Remove unnecessary unmap() functionality from server-side operators to
simplify scheduler architecture and eliminate synthetic operator creation.
Key changes:
- Remove unmap() method from MappedOperator class
- Update TaskInstance.fetch_handle_failure_context() to use original task directly
- Remove unmap() call from SerializedBaseOperator.get_extra_links()
- Update related tests to verify serialization without unmap functionality
The scheduler no longer needs to 'unmap' operators since:
- Callbacks are handled by DAG processor, not scheduler
- Email settings and fail-fast logic work with original task
- Extra links work consistently between regular and mapped operators
This eliminates the TODO comment about moving runtime unmap to task runner
and provides cleaner separation between scheduler and execution concerns.
Includes pre-commit formatting fixes applied by ruff and ruff-format.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

No open projects

Development

Successfully merging this pull request may close these issues.

3 participants

@kaxil@ashb@uranusjr