Skip to main content

fastapi-disconnect

Package version Supported Python versions

Cancel FastAPI request handlers when the client disconnects.

By default, when a client disconnects (timeout, closed tab, network failure), FastAPI keeps executing the request handler to completion. For long-running handlers — an AI flow making paid LLM calls, a heavy database query — that means paying for work nobody is waiting for. This library cancels the handler the moment the client goes away, by listening for the ASGI http.disconnect event (no polling of request.is_disconnected()).

Installation

pip install fastapi-disconnect

Usage

App-wide, via middleware — protects every route, no handler changes:

from fastapi import FastAPI
from fastapi_disconnect import CancelOnDisconnectMiddleware

app = FastAPI()
app.add_middleware(
    CancelOnDisconnectMiddleware,
    exclude_paths=[r"/uploads/.*"],   # optional; re.fullmatch against the path
    on_disconnect=log_cancellation,   # optional; sync or async, gets the ASGI scope
    queue_size=64,                    # optional; bounds body buffering (default: unbounded)
)

on_disconnect runs only when a premature disconnect cancelled a request (not on normal connection close) — a natural place for a metric counting the work cancellation saved you.

Per-endpoint, via decorator — applied below the route decorator:

from fastapi_disconnect import cancel_on_disconnect

@app.get("/generate")
@cancel_on_disconnect
async def generate() -> str:
    return await expensive_llm_flow()

Cooperative, via dependency — for handlers that want to decide when to stop instead of being cancelled preemptively (e.g. finish the current step, checkpoint, then exit):

from fastapi_disconnect import Disconnected

@app.get("/agent")
async def agent(disconnected: Disconnected) -> Result:
    for step in plan:
        if disconnected.is_set():        # free local check, no polling
            return partial_result
        await run_step(step)

Disconnected is an annotated alias for Annotated[asyncio.Event, Depends(disconnected_event)]; the event is set the moment the client disconnects and can also be awaited (disconnected.wait()). Use it instead of the decorator/middleware on a route — combined with them, preemptive cancellation fires first (though the event is still set, which is handy inside shielded cleanup). All three mechanisms share a single per-request watcher, so any combination is safe.

On disconnect, the handler receives a regular asyncio.CancelledError at its next await, so finally blocks and async context managers run as usual. The decorator produces a 499 Client Closed Request response (which goes nowhere — the client is gone — but keeps logs meaningful); the middleware simply stops.

Cleanup on cancellation

Catching CancelledError for cleanup is supported, with one rule: the cancellation is level-triggered (anyio cancel-scope semantics). Once the client is gone, every subsequent await inside the handler raises CancelledError again — so asynchronous cleanup must run in a shielded scope:

import anyio

@app.get("/generate")
@cancel_on_disconnect
async def generate() -> str:
    try:
        return await expensive_llm_flow()
    except asyncio.CancelledError:
        with anyio.CancelScope(shield=True):
            await release_resources()  # runs to completion
        raise

An unshielded await in an except CancelledError or finally block is re-cancelled at its first checkpoint. (asyncio.shield() is not a substitute: it detaches the inner call, but the awaiting handler is still re-cancelled, so the cleanup continues without you.) Synchronous cleanup needs no shielding. Re-raise after cleaning up — a handler that swallows the cancellation and returns a value is treated as having completed normally.

Caveats

  • asyncio only
  • Don't read the raw body (request.body() / request.stream()) inside a guarded handler — the disconnect watcher owns the receive channel while the handler runs. FastAPI-parsed body params are fine, and under the middleware raw reads work normally.
  • The decorator guards only the handler — dependencies and request parsing have already run when it starts, and a returned StreamingResponse body runs after it exits (the decorator warns). Use the middleware to cover the whole request lifecycle. Sync (def) handlers can't be cancelled and are rejected with TypeError.
  • The middleware buffers request bodies eagerly by default — set queue_size to restore upload backpressure (disconnect detection pauses while the queue is full), exclude upload routes, or limit request size upstream.
  • Proxies can hide disconnects — behind a buffering proxy (nginx, ALB) the http.disconnect event may arrive late or never.

License

MIT

Metadata

Release files for fastapi-disconnect 0.4.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for fastapi-disconnect 0.4.0
File Size Uploaded Provenance Actions
fastapi_disconnect-0.4.0.tar.gz 39.3 kB With provenance Details for fastapi_disconnect-0.4.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for fastapi-disconnect 0.4.0
File Interpreter ABI Platform Actions
fastapi_disconnect-0.4.0-py3-none-any.whl Python 3 none any Details for fastapi_disconnect-0.4.0-py3-none-any.whl

Total release size: 48.5 kB

Release files / fastapi_disconnect-0.4.0.tar.gz

Download URL fastapi_disconnect-0.4.0.tar.gz
Size 39.3 kB
Tags Source
SHA-256 checksum
How to use checksums
d60a559823a37f5dc8395933e0f219509af64f0939a98a59ca2a96d27ea3996b
BLAKE2b-256 checksum
How to use checksums
cd2a9a67bf4f6d54b2249cf603a0bc3c40dfc74f9f30ca3641926119cd98b833
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 5, 2026.

Transparency log

Release files / fastapi_disconnect-0.4.0-py3-none-any.whl

Download URL fastapi_disconnect-0.4.0-py3-none-any.whl
Size 9.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ad5444cfc5c946f9e1238837e156de73fe3104e387a249400e3dd655da1557a4
BLAKE2b-256 checksum
How to use checksums
a3a1bdc7bc7109c9d3950415304ca2698ce51911487c2e298ec6a5807a367d24
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 5, 2026.

Transparency log

Security for fastapi-disconnect 0.4.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

Both files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for fastapi_disconnect-0.4.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 5, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.4.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page