I'm trying to perform a request to an http endpoint that streams data for a non-trivial amount of time with Jetty HttpClient. I want to setup a timeout to bound the request time budget. I'm expecting to give up after a precise amount of time in case I'm not receiving any data, but to let the request finish if it started to stream the response.
httpClient.newRequest("http://some-host.local/an/endpoint/that/streams)
.method(HttpMethod.GET)
.idleTimeout(100, TimeUnit.MILLISECONDS)
.timeout(2000, TimeUnit.MILLISECONDS)
.send();
I understand that the request goes trough several states: Queued,Begin, [...], Completed. I found these two timeouts:
timeout()
- Starts on the Queued state; it is disabled on Completed state.idleTimeout()
- Starts after the Begin state; it is reset each time content arrives; it is disabled on Completed state
When many requests are Queued but not yet Begin (e.g. all connections are used), the idleTimeout()
does not apply to them. A request can only be evicted from the queue by a timeout
expiration.
The problem I am facing is that I'm having troubles to set a meaningful timeout that allows me to stop a request that takes too long to start, without also stopping requests that are receiving streamed data.
Is there a way to take into account the time spent awaiting in the queue? I'm trying to bound the time from send()
to first byte received.
CodePudding user response:
Sounds like you have a custom requirement.
Create a custom Listener
, which implements both a selection of RequestListener
and ResponseListener
interfaces.
This custom Listener
will be responsible for tracking requests that "take too long to start" and when the timer has triggered evaluate if the exchange is valid, or should be cancelled via Request.abort()
.
Some key events:
- The
Request.BeginListener
should start your timing for the request (this means the request was created, but not yet queued). - The
Request.QueuedListener
is when the request hits the queue, but has not yet been sent). - The
Request.CommitListener
is when the request has been sent to the remote server. - The
Response.BeginListener
the first line of the response header has been parsed. - The
Response.ContentListener
the first byte of response content has been received.
For other events, check out the other RequestListener
and ResponseListener
classes and their javadoc.
RequestListener
implementations are registered via
httpClient.getRequestListeners().add(mycustomlistener);
ResponseListener
implementations are registered via the Request
object.
client.newRequest(uri)
.onResponseBegin(listener)
.onResponseContent(listener)
.onResponseSuccess(listener)
.onResponseFailure(listener)
.send(listener); // async send (good place to cancel timer on the exchange)