docker / docker/model-runner

diffusers: generation continues after client disconnect and blocks the event loop — no cancellation

Open
#1,041 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Go
Stars
651
Forks
155
PR merge metrics
No merged PRs in 30d

Description

Description

The diffusers backend does not cancel image generation when the requesting client disconnects. A request whose client has timed out or closed the connection still runs to completion — model load included — and the response is written to a socket nobody reads. Subsequent requests queue behind these abandoned jobs, so client-side retries (the natural reaction to a timeout) compound the problem instead of recovering from it.

Likely mechanism (from source)

In python/diffusers_server/server.py, create_image is an async def endpoint that calls the synchronous generate_images pipeline directly — no thread executor, no request.is_disconnected() check, no cancellation path. The blocking call occupies the event loop for the full generation, so the server cannot observe the disconnect even in principle, and every other request serializes behind it.

Environment

  • Docker Model Runner v1.2.6 (Docker Desktop), macOS, Apple Silicon (M1 Pro, 16 GB). The handler is unchanged on current main and in v1.2.7/v1.2.8 release notes.
  • Model: stable-diffusion (DDUF, diffusers backend, MPS float16)

Steps to reproduce

  1. Ensure the diffusers runner is not resident (cold start), so the first request also pays the model load.
  2. POST /engines/diffusers/v1/images/generations with a client timeout shorter than load + generation (e.g. 120 s while the DDUF load alone takes 2+ min on a memory-pressured host).
  3. Let the client time out and close the connection. Send a second request from another client.

Observed

  • The first request's generation starts after its client is gone and runs to completion; the engine logs 200 OK to the disconnected socket. In one instance the host slept mid-queue and the engine completed the abandoned job ~6 hours after the client vanished, immediately on wake.
  • The second request waits behind the abandoned job and can itself time out having never started.
  • The abandoned work holds the model's residency (~7 GB for stable-diffusion) and the GPU for its full duration.

Expected

Client disconnect (or at minimum, connection close before generation starts) cancels the pending/running job — the behavior the llama.cpp chat path already exhibits via request context cancellation. Alternatively: a documented statement that diffusers jobs are uncancellable once accepted, so clients can choose long timeouts over retries.

Impact

Any client that enforces a per-request timeout (agent tool loops, gateways, proxies) turns one slow cold start into a pile-up: each timeout triggers a retry that queues behind a job whose consumer no longer exists.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in python/diffusers_server/server.py at the create_image endpoint and its synchronous generate_images call. Compare the request-context cancellation behavior in the llama.cpp chat path, then reproduce a client disconnect during model load or generation. Done means abandoned work stops or is explicitly documented as uncancellable, without blocking subsequent requests behind it.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
ai, api, backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
52/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.