Open pjfanning opened 6 months ago
Is this issue available for being picked up? I should have time in the next few weeks.
Is this issue available for being picked up? I should have time in the next few weeks.
Sure - this is open for anyone to pick it up
I was taking a look at this. Http().singleRequest(...)
a.k.a Request-Level Client-Side API uses a connection pool (see: PoolInterface) to reuse connections. In order to expose an single request Http2 API(i.e.:Http2().singleRequest(HttpRequest(uri = "http://localhost"))
) and keeping the same behavior of Http().singleRequest
I think we can proceed as follow:
Http2
extension similar to the Http extension with the ** CLIENT **
and ** CONNECTION POOL **
sections.Http
and Http2
Is my understanding / approach right here? Tagging explicitly @raboof as I saw his name in some of the files involved in the changes + some HTTP/2 related work.
A few thoughts here:
singleRequest
/ pool API is to relieve the user of the HTTP connection handling. With HTTP/2 this is less of a concern as a single connection can already support multiple ongoing HTTP requests at the same time.What we already have for HTTP/2:
OutgoingConnection.http2
(returns a Flow
)OutgoingConnection.managedPersistentHttp2
(returns a Flow
)What is missing:
singleRequest
-like APIs using that pool (or on top of one of the existing Flow
returning solutions)In terms of essential functionality, it seems that not much is missing. Many backend usages that need an HTTP/2 client are already supported if you can do the "dispatch to the right host connection" (which only requires that you can keep the single managed connection as a state in your client shim).
I think we can proceed as follow
I don't think we should do it like this. Especially, we don't want another entry point like Http2()
. If we want to allow HTTP2 to be integrated more deeply, it should be done transparently using the existing APIs.
In theory, all existing APIs can be supported by "just" allowing PoolInterface
to deal with HTTP/2. This might not be a trivial task because of assumptions between the PoolInterfaceStage
and NewHostConnectionPool
. Let's say, we ignore automatic negotiation for now and require that you need to configure whether you want to connect to a host via HTTP/1.1 or HTTP/2 (i.e. a new setting in host-connection-pool`).
What needs to be done when HTTP/2 is selected is to replace the code at PoolInterface.apply
, to create an alternative connection flow that uses a single managed persistent HTTP/2 connection instead of the pool of HTTP/1.1 connections.
On the surface, it might be enough to switch out those two lines with the HTTP/2 equivalent. I wouldn't surprised if there are some subtle issues/bugs remaining in managedPersistentHttp2
which was a late addition to HTTP/2 support in akka-http.
You can do protocol negotiation, either by being told that HTTP/2 protocol is available using the alt-svc
HTTP header, or by participating in TLS / ALPN negotiation. In any case, you only get told that HTTP/2 is available relatively late in the connection setup. Since the flows for HTTP/1.1 and HTTP/2 need to be wired differently, it is hard to negotiate on-the-fly and then wire things correctly in a pool setup. That means, you need to run a pre-flight request to figure out whether a certain host would support HTTP/2 and keep that information around for the rest of the session / application runtime. I would see that as an additional future feature. We could keep the http2 selection setting in host-connection-pool
as selecting from http1
/ http2
and then later add auto
or preflight
.
What needs to be done when HTTP/2 is selected is to replace the code at
PoolInterface.apply
, to create an alternative connection flow that uses a single managed persistent HTTP/2 connection instead of the pool of HTTP/1.1 connections.
@samueleresca this is the first thing I would try. Hopefully, the flows implemented by OutgoingConnection.managedPersistentHttp2
and NewHostConnectionPool
are compatible enough for it to work.
OutgoingConnection.managedPersistentHttp2
andNewHostConnectionPool
are compatible enough for it to work
Which is not quite the case right now. NewHostConnectionPool
is Flow[RequestContext, ResponseContext]
while managedPersistentHttp2
is Flow[HttpRequest, HttpResponse]
. That's probably not a blocker, it's more an artifact of the HTTP/1.1 low-level impl not (yet) supporting the more general RequestResponseAssociation
protocol to associated requests with responses that HTTP/2 supports.
@jrudolph Thanks for the steering.
I don't think we should do it like this. Especially, we don't want another entry point like Http2(). If we want to allow HTTP2 to be integrated more deeply, it should be done transparently using the existing APIs.
ACK on the above. So the apporach you are suggesting is to skip the initialization of the NewHostConnectionPool
in case http2 is specified and to use directly the flow coming from managedPersistentHttp2
for constructing the PoolInterface
?
Which is not quite the case right now. NewHostConnectionPool is Flow[RequestContext, ResponseContext] while managedPersistentHttp2 is Flow[HttpRequest, HttpResponse]. That's probably not a blocker, it's more an artifact of the HTTP/1.1 low-level impl not (yet) supporting the more general RequestResponseAssociation protocol to associated requests with responses that HTTP/2 supports.
What is your recommendation here? I'm seeing that [Request|Response]Context
is a case class wrapping a Http[Request|Response]
. Should I create a new PoolInterfaceStage
implementation that handle Flow[HttpRequest, HttpResponse]
instead of Flow[RequestContext, ResponseContext]
?
See https://github.com/matsluni/aws-spi-akka-http/pull/226#issuecomment-1943538007 for context.
It appears that
Http().singleRequest(...)
only supports sending HTTP/1.1 requests.We have samples that use HTTP/2 requests but it might be nice to make it more straightforward.