Repository navigation
Conversation
`--timeout` (default 30 s) is documented as an idle threshold, so that long-running silent tasks can raise it and code that keeps printing is never cut off. Runtime.execute_code passed it to jupyter-kernel-client's execute_interactive, where it is a deadline for the whole run: 0.8.0 and 0.9.0 never enforce it and poll at ~100% CPU once it passes, and 1.0.2 raises TimeoutError even while output flows. For streaming execution without stdin (run, exec, repl), the runtime now waits for kernel messages itself, through the websocket client's execute, get_iopub_msg and get_shell_msg, in blocking slices of up to one second: - Every message from the execution resets the idle clock; messages from other requests are ignored. - After `timeout` seconds without a message it raises TimeoutError, now with a hint to use --timeout. `--timeout 0` (or None) means no limit. - It raises RuntimeError if the connection drops or the kernel dies or restarts, instead of waiting forever. The --timeout help text and the design docs describe the idle semantics. Executions with stdin (auth, drivemount) and the non-streaming path (install, the /content prelude) keep using jupyter-kernel-client. Fixes googlecolab#183
hohieuai
force-pushed
the
fix/timeout-idle-limit
branch
from
October 24, 2026 01:06
7e6cb25 to
e717770
Compare
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.
Fixes #183.
Summary
--timeoutforcolab runandcolab execis documented as an idle threshold: #38 introduced it so users can "increase the idle execution threshold" for silent tasks, and the design docs describe it as protecting long-running silent tasks from being "prematurely killed".Runtime.execute_code, however, passes the value tojupyter-kernel-client'sexecute_interactive, which treats it as a deadline for the whole execution.This PR enforces
--timeoutas the idle limit that the docs describe, and removes the busy wait that the pinned library enters once its deadline passes. The flag and its 30-second default are unchanged.Problem
As measured in #183:
Changes
src/colab_cli/runtime.py: for streaming execution without stdin (colab run,colab exec,colab repl),execute_codecalls a new_execute_streamingmethod. It works on the websocket client behind the kernel client, as_apply_ws_hookalready does, throughexecute,get_iopub_msgandget_shell_msg. These methods are the same in 0.8.0, 0.9.0 and 1.0.2.timeoutseconds, it raisesTimeoutError. The message keeps itsTimeout waiting for outputprefix and now names the limit and points to--timeout.Noneor0means no limit.RuntimeErrorif the websocket drops, or if the kernel reportsdeadorrestarting, instead of waiting forever.execute_codenow describe both timeout behaviors accurately.--timeouthelp text: "Seconds to wait without output before failing (0 for no limit)".docs/: dated log entries, the options table in05_run_command.md, and the timeout bullet in02_execution_and_interactive.md.Behavior change
--timeoutnow fails withTimeoutError, as documented, where it used to complete while a CPU core stayed busy. Forcolab runwithout--keep, the session is then stopped. Users with long silent phases can raise--timeout, or pass--timeout 0.colab replpasses no timeout, so it now waits until each cell finishes, or until the kernel dies or restarts.Scope
These paths still go through
jupyter-kernel-clientand are unchanged:colab authandcolab drivemount, each with an explicit timeout.colab install, and the/contentsetup that runs before each command.colab installpasses no timeout, so a long installation can still hit the library's 10-second deadline. Routing it through_execute_streamingwould be a natural follow-up.Tests
test_colab_runtime_execute_interactive_with_timeoutkeeps its assertion:timeoutreachesexecute_interactive. The call now passesallow_stdin=True, because only that branch still callsexecute_interactive.test_streaming.pykeep their names and assertions. They now useMockKernelClient(tests/mock_kernel.py), which replays scripted kernel messages on a simulated clock. Onlytime.monotonic, as seen byruntime.py, is simulated.--timeouthint in the error;Noneor0;executecalled withallow_stdin=False.0handling or the connection check each makes a test fail.uv run pytest: 373 passed, 19 skipped. Ruff check, format and import sorting pass on the changed files.Verification on Colab runtimes
CPU runtimes, with
jupyter-kernel-client0.8.0, 0.9.0 and 1.0.2:--timeoutcolab run, prints every 5 s for 60 scolab run, silent for 45 sTimeoutError: Timeout waiting for output: no message from the kernel for 30s. Use --timeout to allow longer silences., exit code 1, session stoppedcolab run, silent for 45 scolab run, silent for 45 scolab execon an existing session, prints every 5 s for 60 scolab exec, silent for 45 sTimeoutError, exit code 1colab runFollow-up
With this change, it is safe to raise the
jupyter-kernel-clientpin to>=1.0.2. That change also affectstool.uv.sources, so it is not part of this PR.