elixir-mint / mint

Functional HTTP client for Elixir with support for HTTP/1 and HTTP/2 🌱
Apache License 2.0
1.36k stars 112 forks source link

Flow Control: How to decide whether to stream the body or not #381

Closed mruoss closed 1 year ago

mruoss commented 1 year ago

Hi, it's me again. :)

I'm struggling a bit with HTTP2 Flow Control. In my code I'd like to make a request. Now before I can make that request, I'd like to know based on the body size, whether I can send the body with the request or I need to stream it (by passing the :stream atom to Mint.HTTP.request()).

Mint offers Mint.HTTP2.get_window_size/2 to get the window size of the connection or an open request. BUT, since I haven't opened the request yet, I would need to check whether my body is lager than the connection window size OR the initial window size of a stream/request, right? But The Mint API doesn't offer me to query the initial window size.

Here's roughly what I'd like to do:

def can_send_body?(conn, body) do
    window_size = min(
        Mint.HTTP2.get_window_size(conn, :connection), 
        Mint.HTTP2.get_window_size(conn, :new_request) # or whatever, but it does not exist.
    )
    byte_size(body) <= window_size
end
ericmj commented 1 year ago

Why would you like to send the body with the initial request if you already have the code to stream the body?

mruoss commented 1 year ago

Hmm... good question. We thought it would save us a roundtrip. But thinking about it now, I actually start streaming right after opening the request...

elliottneilclark commented 1 year ago

When I tried streaming the body right after the request it errors out. I needed the ID of the request in order to stream (makes sens). Mint errors out if there's no ID. Even if that id just needs to spread through mint, that adds latency.

ericmj commented 1 year ago

Hmm... good question. We thought it would save us a roundtrip. But thinking about it now, I actually start streaming right after opening the request...

It shouldn't save you a roundtrip unless you call stream/2 between, which you shouldn't have to. Calling request with a body is only a shorthand of using request + stream_request_body.

When I tried streaming the body right after the request it errors out. I needed the ID of the request in order to stream (makes sens). Mint errors out if there's no ID. Even if that id just needs to spread through mint, that adds latency.

Can you elaborate on this, what ID are you referring to? The request function returns a "request reference" that you need to pass to stream_request_body to stream the body. Mint is not exposing stream IDs from the HTTP/2 protocol to users.

elliottneilclark commented 1 year ago

Hmm yeah, the details are a bit hazy as that was early in my debugging. I think I might have been calling request and stream_request_body at the same time and mint was saying that stream_request_body was referring to a request that didn't exist.

mruoss commented 1 year ago

Calling request with a body is only a shorthand of using request + stream_request_body.

That clears all doubts. Thanks.

ericmj commented 1 year ago

Hmm yeah, the details are a bit hazy as that was early in my debugging. I think I might have been calling request and stream_request_body at the same time and mint was saying that stream_request_body was referring to a request that didn't exist.

If that happens it would be a bug, so if you encounter it again please open an issue. But keep in mind that you need to pass the conn returned from request into stream_request_body or the stream reference will be lost to mint.