Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC: Streaming without callbacks #1647

Closed
Tronic opened this issue Jul 26, 2019 · 8 comments
Closed

RFC: Streaming without callbacks #1647

Tronic opened this issue Jul 26, 2019 · 8 comments
Labels

Comments

@Tronic
Copy link
Member

Tronic commented Jul 26, 2019

What do you think on using yield to acquire a response object for streaming? In addition to no-callback pure async code, this would also be extensible to HTTP/2 Server Push, where multiple responses may be sent from one request.

@app.route("/")
async def index(req):
    res = yield sanic.response.text(None)
    await asyncio.sleep(1)
    await res.write("Hello\n")
    await asyncio.sleep(1)
    await res.write("World\n")
    await asyncio.sleep(1)

There is a proof of concept pull request #1645.

@Tronic Tronic changed the title Streaming without callbacks RFC: Streaming without callbacks Jul 27, 2019
@ashleysommer
Copy link
Member

I actually had a similar idea, back when I re-implemented the streaming response type in its current form.
Its not a bad idea.

@Tronic
Copy link
Member Author

Tronic commented Aug 6, 2019

One thing that I am wondering is whether using asyncgen here would lead to issues with connection timeouts or with clean server shutdowns. From my experience with asyncio socket programming, everything just breaks in innumerable unexpected ways, especially when you do anything in the slightest unconventional.

@ahopkins
Copy link
Member

I agree that this is worthwhile to explore.

@Tronic
Copy link
Member Author

Tronic commented Aug 11, 2019

Thanks for the feedback! The current implementation is hackish (implemented with minimal amount of code) but since you like the concept, I'll look closer into it. What comes to asyncgens, I can confidently say that with Trio they pose no issues. With asyncio-- well, more testing is necessary.

@Tronic
Copy link
Member Author

Tronic commented Sep 5, 2019

As mentioned in #1661, the experimentation continues. I believe that a simple await is the way to go, instead of asyncgen (for various technical reasons). Syntax-wise spawning streaming responses by res = await req.respond(headers etc) gets the job done and isn't entirely ugly.

Currently open questions:

  • Should headers be sent during that, or deferred until data is being sent (combine in same IP packet, etc).
  • Response middleware would be run right before sending headers but I haven't found a satisfactory solution for meddling with the streaming data
    • Inheritance to override StreamingResponse methods seems too heavy
    • Callback handles to process body parts aren't exactly pretty either

@Tronic
Copy link
Member Author

Tronic commented Sep 13, 2019

A quick update: respond is no longer async, so you can do simply res = req.respond(). For performance reasons, headers are sent only along with the first call to await res.send(...) where empty data may be given to force headers being sent separately. The middleware issue remains an open question, and since middleware may be async, they cannot be run until the first send.

I'll be in movie shoots and away from keyboard until next Friday.

@stale
Copy link

stale bot commented Dec 12, 2019

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. If this is incorrect, please respond with an update. Thank you for your contributions.

@stale stale bot added the stale label Dec 12, 2019
@Tronic
Copy link
Member Author

Tronic commented Dec 14, 2019

Still relevant, although I won't be able to do much about this right now.

@stale stale bot removed the stale label Dec 14, 2019
@ahopkins ahopkins removed the on hold label Feb 1, 2021
@ahopkins ahopkins closed this as completed Feb 1, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants