sysid / sse-starlette

BSD 3-Clause "New" or "Revised" License
544 stars 37 forks source link

I have a fastAPI stream request, and when I call it on the client, I can interrupt the request. So how do I know the action of this interrupt on the fastAPI server? #61

Closed controZheng closed 1 year ago

controZheng commented 1 year ago
import uvicorn
import asyncio
from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from sse_starlette.sse import EventSourceResponse

times = 0
app = FastAPI()

origins = [
    "*"
]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

@app.get("/sse/data")
async def root(request: Request):
    print(request.client.host)
    event_generator = status_event_generator(request)
    return EventSourceResponse(event_generator)

status_stream_delay = 1  # second
status_stream_retry_timeout = 30000  # milisecond

async def status_event_generator(request):
    global times
    while True:
        if times <= 5:
            yield {
                "event": "message",
                "retry": status_stream_retry_timeout,
                "data": "data:" + "times" + str(times) + "\n\n"
            }
        print(times)
        times += 1
        if times > 5:
            return
        await asyncio.sleep(status_stream_delay)

if __name__ == '__main__':
    uvicorn.run("fastapi_sse:app", host="0.0.0.0", port=5000, log_level="info", reload=True, forwarded_allow_ips='*',
                proxy_headers=True)

I have a fastAPI stream request, and when I call it on the client, I can interrupt the request. So how do I know the action of this interrupt on the fastAPI server?

sysid commented 1 year ago

I am not sure whether I do understand your question, I am afraid. But it does not sound like an sse-starlette issue. If so please re-open with a concrete example where sse-starlette does not behave as expected.

controZheng commented 1 year ago

sse-starlette

How does sse-startlet know if the request has been cancelled ?

Filimoa commented 4 months ago

@controZheng an asyncio.CancelledError is raised.

    try:
        while True:
            async for event in generator(db, params):
                yield {
                    "event": event.event,
                    "data": event.model_dump_json(),
                }
            yield {"event": "stop", "data": {}}
            break

    except asyncio.CancelledError as e:
        logger.info(f"Disconnected from client (via refresh/close) {request.client}")
        raise e

    except HTTPException as e:
        logger.info(f"Disconnected from client (via HTTPException) {request.client}")
        yield {"event": "error", "data": json.dumps({"detail": e.detail})}