Repository navigation
[v3-4-test] Report language SDK runtime launch failures in the task log (#75561) - #75741
Merged
Merged
Conversation
…og (#75561) * Add tests for language SDK tasks that cannot launch * Report language SDK runtime launch failures in the task log * Resolve artifact bundles the same way as native Dag bundles * Fail coordinator bugs before launch without a retry * Say why execute_task uses an ExitStack The lock and the scan roots are entered inside the launch-error guard but released only after wait() returns, which is the whole reason the stack is there rather than a plain with. * Fail an unsupported supervisor schema version without a retry A worker whose Task SDK does not know the schema version an artifact speaks cannot learn it by trying again, so the task should not burn its retries on it. The check also moves out of the native Dag branch and now runs once for every task, so an artifact found by scanning the bundle is rejected before the runtime starts rather than by the attrs validator inside start(). * Write a failed launch's runtime output to the task log The output a runtime wrote before it failed to connect went into the error message, so the task log rendered it as one event whose continuation lines carry no timestamp or level. It now goes to the log the way a connected runtime's output does, one event per line under task.stdout and task.stderr, and the message stays on one line. The kept tail grows to 16 KiB, since a JVM or Node stack trace does not fit in 4 KiB, and says so when it drops earlier output. Draining a runtime that keeps printing while it never connects is capped, so it cannot hold up the failure. * Assert why a runtime that cannot be executed fails The test matched the path with a wildcard, which hid whether the reason the OS gave survives the wrap. It now asserts the whole message, and covers a runtime that exists but cannot be executed as well as one that is missing. _connect_without_output moves above the class that uses it, where every other helper in the file sits. * Keep the runtime's sockets tracked until the launch has finished The pipes and the accepted connections were untracked as the argument to _register_pipe_readers, so they were disowned before it ran. A failure in it, or in _on_child_started after it, left four sockets that nothing closed: the tracker no longer owned them and the half-built subprocess was discarded. They now stay with the tracker until the task instance has started, which is the point 'self' takes them over and closes them in wait(). * Forward a failed launch's output through the supervisor's forwarder _report_startup_output decoded and logged the lines itself, which repeated forward_to_log with small differences. It now feeds forward_to_log instead, so a failed launch and a connected runtime split lines and decode them the same way. The loggers to forward to come from WatchedSubprocess._target_loggers, split out of _get_target_loggers so both callers share it: 'self' does not exist yet when the runtime fails to connect, and the module logger the tuple ends with belongs to supervisor.py. * State the launch-error contract in terms of the task instance TaskLaunchError said a coordinator raises it "before it starts the runtime", but a runtime that exits or times out before connecting has already been spawned. The invariant custom coordinators implement against is that the task instance has not been started, which is what the supervisor does itself when it handles the error. The command builders now also say to raise TaskLaunchError with an explicit retryable when the implementation knows the answer, rather than leaving it to be guessed from the exception type. * Drop the comment on execute_task's ExitStack * Say what a cleared task does to a failed launch's output "the log keeps output for a try that never ran" reads as if the output shows up against the next try. It does not: the log file is rendered per try, so the lines stay in the file of the try whose launch failed. What happens is narrower, and worth naming: the supervisor stops without reporting a state, so the file is never uploaded and is left on the worker. * Keep a Dag file command's launch error and its retryability * Expect a launch error when a runtime dies before connecting The process group test landed on main while this branch was open, against the RuntimeError _accept_connections raised there. This branch raises TaskLaunchError instead, which is not a RuntimeError. --------- (cherry picked from commit 21a8a98) Co-authored-by: ChickenBenny <zxc123benny14159@gmail.com> Co-authored-by: ZHE YOU LIU <zhu424.dev@gmail.com>
jason810496
marked this pull request as ready for review
October 27, 2026 10:10
jason810496
requested review from
amoghrajesh,
ashb,
jason810496 and
uranusjr
as code owners
October 27, 2026 10:10
jason810496
approved these changes
Oct 27, 2026
jason810496
enabled auto-merge (squash)
October 27, 2026 10:11
vatsrahul1001
disabled auto-merge
October 27, 2026 10:44
Contributor
Author
|
Hi maintainer, this PR was merged without a milestone set.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Add tests for language SDK tasks that cannot launch
Report language SDK runtime launch failures in the task log
Resolve artifact bundles the same way as native Dag bundles
Fail coordinator bugs before launch without a retry
Say why execute_task uses an ExitStack
The lock and the scan roots are entered inside the launch-error guard but
released only after wait() returns, which is the whole reason the stack is
there rather than a plain with.
A worker whose Task SDK does not know the schema version an artifact speaks
cannot learn it by trying again, so the task should not burn its retries on
it. The check also moves out of the native Dag branch and now runs once for
every task, so an artifact found by scanning the bundle is rejected before
the runtime starts rather than by the attrs validator inside start().
The output a runtime wrote before it failed to connect went into the error
message, so the task log rendered it as one event whose continuation lines
carry no timestamp or level. It now goes to the log the way a connected
runtime's output does, one event per line under task.stdout and task.stderr,
and the message stays on one line.
The kept tail grows to 16 KiB, since a JVM or Node stack trace does not fit
in 4 KiB, and says so when it drops earlier output. Draining a runtime that
keeps printing while it never connects is capped, so it cannot hold up the
failure.
The test matched the path with a wildcard, which hid whether the reason the
OS gave survives the wrap. It now asserts the whole message, and covers a
runtime that exists but cannot be executed as well as one that is missing.
_connect_without_output moves above the class that uses it, where every
other helper in the file sits.
The pipes and the accepted connections were untracked as the argument to
_register_pipe_readers, so they were disowned before it ran. A failure in it,
or in _on_child_started after it, left four sockets that nothing closed: the
tracker no longer owned them and the half-built subprocess was discarded.
They now stay with the tracker until the task instance has started, which is
the point 'self' takes them over and closes them in wait().
_report_startup_output decoded and logged the lines itself, which repeated
forward_to_log with small differences. It now feeds forward_to_log instead,
so a failed launch and a connected runtime split lines and decode them the
same way.
The loggers to forward to come from WatchedSubprocess._target_loggers, split
out of _get_target_loggers so both callers share it: 'self' does not exist
yet when the runtime fails to connect, and the module logger the tuple ends
with belongs to supervisor.py.
TaskLaunchError said a coordinator raises it "before it starts the runtime",
but a runtime that exits or times out before connecting has already been
spawned. The invariant custom coordinators implement against is that the
task instance has not been started, which is what the supervisor does itself
when it handles the error.
The command builders now also say to raise TaskLaunchError with an explicit
retryable when the implementation knows the answer, rather than leaving it
to be guessed from the exception type.
Drop the comment on execute_task's ExitStack
Say what a cleared task does to a failed launch's output
"the log keeps output for a try that never ran" reads as if the output shows
up against the next try. It does not: the log file is rendered per try, so
the lines stay in the file of the try whose launch failed. What happens is
narrower, and worth naming: the supervisor stops without reporting a state,
so the file is never uploaded and is left on the worker.
Keep a Dag file command's launch error and its retryability
Expect a launch error when a runtime dies before connecting
The process group test landed on main while this branch was open, against
the RuntimeError _accept_connections raised there. This branch raises
TaskLaunchError instead, which is not a RuntimeError.
(cherry picked from commit 21a8a98)
Co-authored-by: ChickenBenny zxc123benny14159@gmail.com
Co-authored-by: ZHE YOU LIU zhu424.dev@gmail.com