sanic-org / sanic

Accelerate your web app development | Build fast. Run fast.

Home Page:https://sanic.dev

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Response Streaming doesn't work

trungtin opened this issue · comments

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

This basic demo that I copied from the documentation doesn't seem to work.

import time
import os

from sanic import Sanic
from sanic.request import Request

app = Sanic("test")

@app.route("/")
async def test(request: Request):
    response = await request.respond(content_type="text/csv")
    await response.send("foo,")
    await response.send("bar")
    await response.send("\n")
    time.sleep(2)
    await response.send("foo,")
    await response.send("bar")

    await response.eof()

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=int(os.environ.get('PORT', 8008)), dev=True)

I tested with

curl -X GET -N http://localhost:8008/

Code snippet

No response

Expected Behavior

Should stream the response to the stdout, instead, it only send the whole response as one

How do you run Sanic?

As a script (app.run or Sanic.serve)

Operating System

MacOS Ventura 13.1

Sanic Version

22.12.0

Additional context

No response

Your snippet is faulty.

You are sending the first three chunks in very short succession, so you will almost assuredly never notice those.

Then, time.sleep is a blocking operation, so it is essentially blocking the buffer drain. Following this with a couple more short messages and it will appear to show up all at once. Try spreading it out more with no i/o blocking.

from asyncio import sleep

...

@app.get("/")
async def handler(request: Request):
    response = await request.respond(content_type="text/csv")
    await response.send("foo,")
    await sleep(1)
    await response.send("bar")
    await sleep(1)
    await response.send("\n")
    await sleep(1)
    await response.send("foo,")
    await sleep(1)
    await response.send("bar")

    await response.eof()
commented

Sanic does not send data even with asyncio.sleep(2).
But with '\n',newline. Sanic sends data imediately.
│ Sanic v21.12.2 │

import time
import os
import asyncio

from sanic import Sanic
from sanic.request import Request

app = Sanic("test")


@app.route("/")
async def test(request: Request):
    response = await request.respond(content_type="text/plain")
    for i in range(10):
        await response.send(f"{i}foo,")
        await asyncio.sleep(0.1)

    for i in range(10):
        await response.send(f"{i}foo,\n")
        await asyncio.sleep(0.1)

    await response.eof()

I didn't test this but more likely you are using curl to test and it doesn't flush output to your terminal except on newline. Try with a browser.

commented

@Tronic Thank you very much. It's my problem.
Use curl http://127.0.0.1:8000/tt -N can get right result