Serialized HTTP requests with asynchronous responses

248 views
Skip to first unread message

Donovan Hide

unread,
Sep 26, 2017, 1:40:38 AM9/26/17
to golang-nuts
Hi,

I have an interesting problem where I need to make a rapid series of HTTP requests to the same host, each with a nonce which increments with each request and a signature of the request body including that nonce, but I don't want to wait for the response before sending the next request. The nonces must be received by the host in ascending order.

I've tried this using standard library HTTP requests, each running in separate goroutines with a time delay before releasing the next nonce, to try and ensure that the requests are sent in order, but this fails intermittently, possibly due to network delays. I've also looked at PipelineClient with MaxConns set to 1, which seems closer to what I need, but it would still require an asynchronous response to prevent blocking between request dispatches.


Has anyone battled a problem similar to this before? Any ideas much appreciated!

Cheers,
Donovan.

Diego Medina

unread,
Sep 26, 2017, 11:09:32 AM9/26/17
to golang-nuts
Hi,

Probably not the answer you were expecting, but :

> The nonces must be received by the host in ascending order.

is going to fail sooner or later, no matter which trick/feature you use. A more robust solution would be to code the server to accept unordered requests and handle them gracefully.

To give you a concrete example or where such assumption/requirement fails:

1. first requests goes out
2. server starts reading the request including the nonce
3. second request goes out with a new nonce
4. the network from req 1 fails so the server did not finish reading the complete payload
5. req from step 3 finishes

Now the server **doesn't** have req 1. The higher the concurrency, the higher the chances of this issue from happening and being harder to handle from the client side.

Or , would something like this https://github.com/savaki/snowflake help you by creating unique IDs with *some* ordering?

Final question, is the nonce used anywhere as a cryptographic IV/Salt/etc? If so, I wouldn't use an ID that increments, but instead use something really random, like crypto/rand


Regards,

Diego

Donovan Hide

unread,
Sep 26, 2017, 4:16:40 PM9/26/17
to Diego Medina, golang-nuts
The nonce is intended just to stop replay attacks. It doesn't have to increment with a delta of 1, typically you just use time.UnixNano(). The API is not under my control, I just want to minimise the occurrence of nonces being received out of order by the API.

Gabriel Sullice

unread,
Sep 27, 2017, 8:45:03 AM9/27/17
to golang-nuts
If it's imperative they're received in order, you cannot do anything accept wait for at least the first byte of the response. You'll never know if the request was fully received until that point. Even then, only that it was _received_, not validated (e.d. 400 response).

If it is _not_ imperative and you only want to "minimize" the occurrences. You can probably try to use a dynamic timeout value rather than a fixed value.

For example, on every request, meausure the time to the first byte of the response. Send the second request when that first byte is received. If the first response took 200ms, send the third request at 100ms (half of the round-trip) after the second. If the first byte of the second response is received in only 100ms, try adjusting the timeout to 50ms. Repeat this process ad infinitum. If you really want to get fancy, you could use a beyesian formula to take into account more than just the most recent response time.

Finally, you may be able to get away with less than just .5 * TTFB. However, the lower you make the timeout, the more likely it will be that you send requests out of order.

Donovan Hide

unread,
Sep 27, 2017, 9:52:14 AM9/27/17
to Gabriel Sullice, golang-nuts
Seems like a simple solution is just to write HTTP requests over a single TLS connection and queue the requests and responses in order. Can't handle redirects or reconnections, but works for my purposes:

Reply all
Reply to author
Forward
0 new messages