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()
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.