Home / Guides / Stop LLM generation after cancel

How to stop your LLM generating tokens after a user cancels

In Sorami’s tests, a transport close stopped vLLM 0.31.0 at the abandon point. Clients that kept the connection did not.

Published · Based on our tokens-after-cancel research

Last reviewed: · 5 min read

Close the HTTP connection. In Sorami’s tokens-after-cancel study on vLLM 0.31.0, a transport close stopped generation at the abandon point in every arm tested, while a client that kept reading or held the socket unread left the engine running. Close each timed-out attempt before retrying, test your gateway, and log engine-side terminals.

The journals, plans and analysis are in Sorami’s public data repository. This guide takes only steps the report supports: one Kubernetes cluster in AWS and six fresh-engine blocks per arm, with synthetic prompts and greedy decoding. Engines, versions and gateways that were not run are not covered.

Key takeaways

  • A transport close left 0.0 accepted tokens after the close on vLLM 0.31.0.
  • Draining accepted 52.8 more tokens per abandoned request; an unread socket 44.3 more.
  • LiteLLM 1.105.1 passed the close through; Bifrost transports/v2.3.0 added about 3 tokens.
  • SGLang 0.5.21 let 2.0 tokens through after a close; an unread socket stayed alive.

What did the study measure?

An in-process observer on the engine scheduler counted scheduler-accepted tokens, not what the client saw. Three client behaviours were compared after the same abandon point: a transport close, a drained walk-away (keep reading to the end) and a bounded no-read (hold the socket unread for 5 s and then close). Each ran under abandonment after 8 chunks and under a 1.5 s attempt deadline with retry.

On vLLM 0.31.0 with Qwen3-8B on one NVIDIA L4, the close left 0.0 tokens after the close; under retries, draining left 147.9 orphan tokens per task against 0.0 for the close. The same direction held for gpt-oss-20b on L4 and A10G, at batch 64, on free-form prompts and under tensor and pipeline parallelism. gpt-oss-20b was not run in parallel.

How do you make a cancel reach the engine?

1. Close the connection; stopping the read is not a cancel

The engine learns about a cancel only when the transport closes, so the stop button must close the HTTP connection. In Python that is stream.close() or leaving the stream’s context manager (openai-python); in Node, breaking out of the for await loop aborts the request (openai-node); with fetch, pass an AbortSignal and call abort(). Stopping the read while leaving the socket open is the unread-socket condition: 44.3 more tokens per request than a close on vLLM, and 155.1 orphan tokens per set on SGLang under retries.

with client.chat.completions.create(model=MODEL, messages=msgs, stream=True) as stream:
    for chunk in stream:
        if user_cancelled():
            break   # leaving the block calls stream.close()

2. Close every attempt you replace before you retry

A timed-out attempt that was not closed kept decoding beside its replacement. On one L4, closing the stale attempt took completion within the deadline from 20.7% (drained) and 11.3% (no-read) to 38.0%. Abort the first attempt’s connection, then send the retry.

3. Test the close through your gateway

LiteLLM 1.105.1 passed the client close through with no extra engine tokens, and its 1 s timeout stopped the upstream under every client condition. Bifrost transports/v2.3.0 closed the upstream about 3 tokens later, and its 1 s timeout did not stop the upstream unless the client closed. A 502 after engine admission doubled engine work on both gateways (61.95 orphan tokens per set). Run the harness against your own gateway before trusting either number.

4. Give SGLang requests a server-side deadline

SGLang 0.5.21 detects a disconnect when its next write fails and polls a wait queue with a 4 s timeout (tokenizer manager source). In the study that meant 2.0 tokens after a close and a 120 ms terminal. Under retries the close-to-terminal mean was 2,300 ms, unexplained in the report, and the unread socket did not stop retried requests. Add your own deadline.

5. Log engine-side terminals and alert on late ones

Client token counts miss everything produced after the client looks away, and reasoning models produce hidden tokens before the first visible chunk. Log each request’s terminal status and accepted token count at the engine, matched to the client close time. Tokens accepted after the close are the orphan signal.

6. Treat hosted metering as a dated observation

On 7 October 2026, with one prompt shape, hanging up stopped the meter short of the full answer on every OpenRouter and Amazon Bedrock route tested. Those are provider-reported usage figures, not an invoice, and they were not rerun. Check your provider’s generation records against delivered text yourself.

Sorami’s view

This section is opinion. Most orphan generation we measured came from client and gateway behaviour, not the engine, so fix the stop button and the retry path first. Pick a gateway on measured cancel behaviour, and keep a server-side deadline on SGLang until its queue behaviour under load is explained. Request cancellation belongs beside rate limits and timeouts in an AI production readiness review; if serving spend is the question, a cloud cost review looks at the GPU hours around it.

Checklist

  • Close the HTTP connection on cancel; stopping the read is not a cancel.
  • Abort each timed-out attempt before sending its retry.
  • Test the close and the timeout through your gateway with the harness.
  • Abort upstream when the gateway returns an error for an admitted request.
  • Set a server-side deadline on SGLang requests under load.
  • Log engine-side terminals with status and token count, matched to the close.
  • Count reasoning-model tokens at the engine, not from client chunks.

The full technical report has the method, tables, figures and limits. For the network side of the same stacks, see how to secure Ray and vLLM on Kubernetes. More is in the guides index.

Sources

Questions before you book

Practical answers.

Does stopping the stream on the client stop the GPU?

Only if the client closes the HTTP connection. In Sorami’s tests on vLLM 0.31.0, a transport close left 0.0 scheduler-accepted tokens after the close. A client that kept reading accepted a mean 52.8 more tokens per abandoned Qwen3-8B request, and one that held the socket unread for 5 s accepted 44.3 more.

Does an LLM gateway cancel the upstream request for me?

It depends on the gateway and on whether the client closed. LiteLLM 1.105.1 passed a client close through with no extra tokens, and its 1 s timeout stopped the upstream under every client condition tested. Bifrost transports/v2.3.0 closed the upstream about 3 tokens later, and its 1 s timeout did not stop the upstream unless the client closed.

Is SGLang the same as vLLM after a cancel?

Not in this study. SGLang 0.5.21 let 2.0 tokens through after a close and reached its terminal 120 ms after the close, against 0.0 tokens and 61 ms on vLLM 0.31.0. An unread socket did not stop SGLang’s retried requests, which left 155.1 orphan tokens per set, and under retries the close-to-terminal mean was 2,300 ms.

What should I log to find orphan generation?

Engine-side request terminals with their status and token count, matched to the client-side close time. In the study the observer journalled admission, each accepted token batch and the logical terminal per request. A request that accepted tokens after the client closed, or an aborted request with a late terminal, is the signal to alert on.

Do hosted providers keep metering after a hangup?

In dated observations from 7 October 2026 on one prompt shape, hanging up stopped the meter short of the full answer on every OpenRouter and Amazon Bedrock route tested. Those are provider-reported usage figures, not an invoice, and they were not rerun for the current report.

Next step

Want these checks run on your own serving stack? The AI production readiness review covers request cancellation beside rate limits, timeouts and the other controls an LLM service needs before launch. Contact us to discuss scope.

About Sorami

Sorami is an Australian cyber security and cloud consultancy. We build and secure cloud environments, Kubernetes and AI agents, and the senior engineers who scope the work deliver it themselves. To discuss this research or a review of your own stack, use the form below. Only your email is required, and we reply within one business day.

An enquiry, not a booking. We use your details only to reply. See our privacy notice, or go to the contact page.

Let’s scope it

Running vLLM, SGLang or a gateway in production?

Tell us how requests reach your engine. We will scope a review of cancellation, timeouts and retries on your own stack.

Send an enquiry