Resume sessions - #13585
Conversation
# Conflicts: # js/gallery/Gallery.test.ts # js/gallery/shared/Gallery.svelte
🪼 branch checks and previews
Install Gradio from this PR pip install https://huggingface.co/buckets/gradio/pypi-previews/resolve/b4d4ff1d4401f74622b4fb39fc8682b7d6f5e097/gradio-6.22.0-py3-none-any.whlInstall Gradio Python Client from this PR pip install "gradio-client @ git+https://github.com/gradio-app/gradio@b4d4ff1d4401f74622b4fb39fc8682b7d6f5e097#subdirectory=client/python"Import Gradio JS Client from this PR via CDN import { Client } from "https://huggingface.co/buckets/gradio/npm-previews/resolve/b4d4ff1d4401f74622b4fb39fc8682b7d6f5e097/browser.js"; |
🦄 change detectedThis Pull Request includes changes to the following packages.
|
There was a problem hiding this comment.
Pull request overview
Adds opt-in “resume sessions” support so queued jobs can survive brief disconnects/page refreshes by reconnecting to the same session_hash + event_id, replaying buffered queue output, and then acknowledging completion to clear server/client recovery state.
Changes:
- Backend queue: track per-session message history, mark sessions detached/attached, expire detached sessions via TTL, and add a new
/queue/ackendpoint for explicit completion acknowledgement. - Frontend client: persist active queued
event_ids in browser storage, reconnect SSE streams withresume_event_id, and acknowledge completed events to clear recovery state. - Tests: add unit coverage for client stream reconnect/session storage and a backend test validating detached session resumption + acknowledgement cleanup.
Reviewed changes
Copilot reviewed 20 out of 20 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| test/test_queueing.py | Adds backend test covering detach → resume replay → ack cleanup flow. |
| js/spa/test/cancel_events.spec.ts | Updates expectation: iterative job continues after page close. |
| js/spa/src/Index.svelte | Enables resume_sessions for the SPA client connections. |
| js/core/src/dependency.ts | Acknowledges submissions and adds dependency-level resume flow. |
| js/core/src/Blocks.svelte | Resumes events on ready when resumable events exist, otherwise dispatches load events. |
| js/app/src/routes/[...catchall]/+page.ts | Enables resume_sessions in SvelteKit load client connect. |
| js/app/src/routes/[...catchall]/+page.svelte | Enables resume_sessions on reconnect in the app page. |
| gradio/routes.py | Adds resume params to /queue/data, session attach/detach handling, and /queue/ack. |
| gradio/queueing.py | Adds message history, detach TTL tracking, resume/ack helpers, and expiry cleanup. |
| gradio/data_classes.py | Introduces QueueAckBody request model. |
| client/js/src/utils/submit.ts | Adds resumable-event tracking, resume submission path, and acknowledgement hook. |
| client/js/src/utils/stream.ts | Adds SSE reconnect/backoff, resume query params, and “normal close” reopening. |
| client/js/src/utils/session.ts | New session storage + cookie utilities for resumable queued events. |
| client/js/src/types.ts | Adds resume_sessions option and SubmitIterable.acknowledge(). |
| client/js/src/test/stream.test.ts | Adds coverage for normal close reopen + reconnect/resume behavior. |
| client/js/src/test/session.test.ts | Adds coverage for session storage semantics and SSR cookie read. |
| client/js/src/test/init.test.ts | Adds test ensuring sessions are not restored across different apps. |
| client/js/src/constants.ts | Adds ACK_URL constant. |
| client/js/src/client.ts | Adds restored session hash support, resume helper, and reconnect timer cleanup. |
| .changeset/quiet-sessions-return.md | Announces minor feature release for both gradio and @gradio/client. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Resolve conflicts by keeping soft-reload from main and acknowledging resumable submissions before clear_submission. Co-authored-by: Cursor <cursoragent@cursor.com>
|
I haven't had a chance to test this yet, but a few things that come to mind:
|
# Conflicts: # js/app/src/routes/[...catchall]/+page.svelte # js/core/src/dependency.ts # js/spa/src/Index.svelte
|
I tried this out on a ZeroGPU Space and the resume flow works nicely. One thing I noticed while testing: closing the tab no longer cancels jobs. On 6.20.0 a running generator stops as soon as the tab closes (the The two cases do seem distinguishable from the client side, though: closing the tab or navigating away fires Either way, it would be good to document the change and give app authors a way to tune or opt out of it. Right now the only knob is the undocumented A few smaller things I noticed:
|
# Conflicts: # client/js/src/client.ts # client/js/src/test/init.test.ts # client/js/src/utils/submit.ts
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 32 out of 32 changed files in this pull request and generated no new comments.
Suppressed comments (5)
client/js/src/utils/stream.ts:109
open_stream()retries the SSE connection on any stream error, regardless ofresume_sessions. This breaks the “opt-in” guarantee for existing JS clients and also means callers won’t receive thebroken_connectionmessage they currently handle insubmit.ts.
Consider preserving the old behavior when resume_sessions is false: dispatch a broken_connection message to active callbacks and return without scheduling reconnect; only do the resume/reconnect path when resume_sessions is true.
stream.onerror = async function (e) {
if (that.stream_instance !== stream) {
return;
}
console.error(e);
client/js/src/utils/stream.ts:1
- The SSE stream currently always schedules automatic reconnects on
onerror, even whenoptions.resume_sessionsis not enabled. That changes existing JS client behavior (previously it surfaced abroken_connectionto callbacks and did not attempt to resume jobs) and effectively makes session resume non-opt-in.
This issue also appears on line 105 of the same file.
import { SSE_URL } from "../constants";
js/spa/test/cancel_events.spec.ts:2
- This Playwright test that asserted “closing the page stops the Python function” was removed, but the PR description introduces new close semantics (
/queue/closewith a ~5s grace) that should still be covered end-to-end. Without a replacement, regressions could leave abandoned jobs running and holding queue/GPU resources.
Recommend reintroducing an updated test that closes the page, waits slightly longer than the close grace period, then asserts the server-side job stopped/cleaned up (adjusting assertions to the new timing/behavior).
import { test, expect } from "@self/tootils";
client/js/src/utils/stream.ts:55
- If
this.stream(url)returns null/undefined,stream_status.openhas already been set totrueand never reset. That leaves the client thinking an SSE stream is open and prevents future reconnect attempts.
if (!stream) {
console.warn("Cannot connect to SSE endpoint: " + url.toString());
return;
}
.changeset/quiet-sessions-return.md:5
- This repo’s contribution guidelines explicitly ask contributors not to add
.changeset/*.mdfiles manually because a GitHub Action generates them from the PR title (and a hand-written changeset will silently replace the title in the changelog). Please remove this changeset file and rely on the Action instead.
---
"@gradio/client": minor
"gradio": minor
"gradio_client": minor
---
Description
Quick summary: an active queued job can now survive a refresh or short connection drop without being submitted again.
GRADIO_QUEUE_SESSION_RESUME_TTL.demo.load()handlers still run on a resumed page.resume_sessions: trueand callresume_jobs([{ event_id, fn_index }]).Client(..., resume_sessions=True), saveclient.session_hash,job.wait_for_id(), andjob.fn_index, then callresume_jobs(..., session_hash=...)from a new client. A running client also reconnects automatically after a short network failure.Closes: #13584
Closes: #8368
Screen.Recording.2026-07-16.at.3.36.05.PM.mov
AI Disclosure
Testing and Formatting Your Code
No Playwright tests were added.