Skip to content

[cherry-pick][2.58.0][core][taskEvents out of GCS][3/n] Export task events from aggregator agent to dashboard head (#65028) - #65275

Open
elliot-barn wants to merge 1 commit into
releases/2.58.0from
elliot-barn/cherry-pick-2.58.0-agg-to-dashboard-65028
Open

[cherry-pick][2.58.0][core][taskEvents out of GCS][3/n] Export task events from aggregator agent to dashboard head (#65028)#65275
elliot-barn wants to merge 1 commit into
releases/2.58.0from
elliot-barn/cherry-pick-2.58.0-agg-to-dashboard-65028

Conversation

@elliot-barn

Copy link
Copy Markdown
Collaborator

Cherry-pick of #65028 (merge commit 3ca1915) into releases/2.58.0.

One contextual conflict in src/ray/common/ray_config_def.h: on master, #64835 added its enable_ray_task_event_recorder flag adjacent to this PR's enable_task_events_to_dashboard_head flag. Resolved by inserting only this PR's flag, so this cherry-pick is independent of #65274 (the #64835 pick) and the two can merge in either order. All other files applied cleanly.

Not a duplicate: no existing open PR against releases/2.58.0 contains this change. Cherry-picked with AI assistance (Claude Code); pre-commit hooks ran and passed on the commit.

🤖 Generated with Claude Code

… agent to dashboard head (#65028)

Part of the effort to move task-event observability data out of GCS and
onto the
dashboard head. This PR adds support for moving task events from
aggregator agent to dashboard head. Changes are as follows:

1. Adds a new module `task_events_head` that hosts a POST
`/api/task_events` endpoint to receive task events from the aggregator
agent. For now it just buffers received events in memory. More stuff to
be done in upcoming PRs.
2. Adds a new publisher client `AsyncDashboardHeadPublisherClient` and a
corresponding flag to `PUBLISH_EVENTS_TO_DASHBOARD_HEAD`.
3. The existing publisher `AsyncGCSTaskEventsPublisherClient` is still
kept since some tests depend on it. This will be removed later after the
entire migration completes.
4. The new publisher client is similar to
`AsyncGCSTaskEventsPublisherClient` in that it has the same event
selection to export and has the same proto building, but sends the
request over HTTP POST instead of a gRPC call.
5. Each of the two publishers gets its own dropped-task-attempts
metadata buffer, since`TaskEventsMetadataBuffer.get()` is destructive
and a shared buffer would split the metadata across publishers.
6. The publisher resolves the dashboard head's address lazily from
InternalKV (DASHBOARD_ADDRESS) via `gcs_client`, then makes the POST
request. If the address isn't registered yet the publish is marked
unsuccessful and the publisher retries on its next cycle; once resolved,
the endpoint is cached.

---------

Signed-off-by: Kartica Modi <karticamodi@gmail.com>
(cherry picked from commit 3ca1915)
Signed-off-by: elliot-barn <elliot.barnwell@anyscale.com>
@elliot-barn
elliot-barn requested a review from a team as a code owner August 7, 2026 01:51

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces the capability to migrate task events from GCS to the dashboard head. It adds a new configuration flag enable_task_events_to_dashboard_head, implements AsyncDashboardHeadPublisherClient to publish task events over HTTP, and introduces TaskEventsHead to receive and buffer these events. Feedback on the changes highlights two key improvements: setting a maxlen on the collections.deque in TaskEventsHead to prevent unbounded memory growth and potential OOM crashes, and catching the broader aiohttp.ClientError exception to ensure the cached endpoint is cleared on HTTP response errors.

# TODO(karticam): Replace this with an in-memory store of task events.
# This will mimic current GcsTaskManager and will power state API.
# Will be done in future PRs.
self._events = collections.deque()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

The collections.deque is initialized without a maxlen parameter. Since TaskEventsHead receives task events continuously from all nodes in the cluster and appends them to self._events indefinitely, this will lead to unbounded memory growth and eventual Out-Of-Memory (OOM) crashes of the dashboard head process.

Consider setting a sensible maxlen (e.g., 100000 to match the default GCS task events limit) to ensure memory usage remains bounded.

Suggested change
self._events = collections.deque()
self._events = collections.deque(maxlen=100000)

Comment on lines +408 to +413
except (aiohttp.ClientConnectionError, asyncio.TimeoutError):
# Couldn't reach the endpoint; the dashboard head may have restarted at a
# new address. Drop the cached endpoint so the next publish re-resolves it
# from InternalKV.
self._endpoint = None
raise

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Currently, the cached self._endpoint is only cleared when aiohttp.ClientConnectionError or asyncio.TimeoutError is raised. However, if the dashboard head restarts or is redeployed, the old endpoint might return HTTP errors (e.g., 404 Not Found or 503 Service Unavailable) via resp.raise_for_status(), which raises aiohttp.ClientResponseError.

Catching the broader aiohttp.ClientError (which is the base class for both connection and response errors) ensures that the cached endpoint is also cleared on HTTP response errors, allowing the client to re-resolve the correct endpoint from GCS on the next publish attempt.

Suggested change
except (aiohttp.ClientConnectionError, asyncio.TimeoutError):
# Couldn't reach the endpoint; the dashboard head may have restarted at a
# new address. Drop the cached endpoint so the next publish re-resolves it
# from InternalKV.
self._endpoint = None
raise
except (aiohttp.ClientError, asyncio.TimeoutError):
# Couldn't reach the endpoint or received an HTTP error; the dashboard head may
# have restarted at a new address. Drop the cached endpoint so the next publish
# re-resolves it from InternalKV.
self._endpoint = None
raise

@ray-gardener ray-gardener Bot added the core Issues that should be addressed in Ray Core label Aug 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core Issues that should be addressed in Ray Core

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants