http.Client timeouts

1,246 views
Skip to first unread message

Sanjay Menakuru

unread,
Mar 18, 2012, 9:17:56 PM3/18/12
to golan...@googlegroups.com
Hey golang-nuts,

With the new SetDeadline-style methods on net.Conn, there seems to be no way to make a http request that has a timeout, taking into account redirects, and keep-alive connections.
Previously, I would do this by providing my own Dial function and setting the Conn's timeout, which, as I understand it, was a flawed technique anyways.
But now, there doesn't seem to be a clean way to do it.

Please let me know if there is a clean way to handle this that I am overlooking.

Thanks,
Sanjay

Kyle Lemons

unread,
Mar 19, 2012, 4:04:21 PM3/19/12
to Sanjay Menakuru, golan...@googlegroups.com
The same technique seems like it would work.  The difference is that the timeout applies to all reads as a whole, not to each individual read call.  I don't think, however, this plays nicely with the client pooling.

Sanjay Menakuru

unread,
Mar 19, 2012, 10:45:19 PM3/19/12
to golan...@googlegroups.com, Sanjay Menakuru
It doesnt play nicely with connection pooling or redirects as far as I can tell. That is to say, if you set a timeout 10 seconds in the future, with a RedirectFunc that allows 3 redirects, then the three HTTP requests are sharing the timeout. There's no way to say *each* request gets 10 seconds.

In my case, I'm making internal calls, so I want to set the timeouts to extremely low values. So more like 20ms per redirect, max 3 redirects as a policy. This could be handled by setting Deadline to 60ms in the future (not strictly the same thing, but close enough), but connection pooling breaks...

Sanjay

Kyle Lemons

unread,
Mar 20, 2012, 1:11:10 PM3/20/12
to Sanjay Menakuru, golan...@googlegroups.com
The solution probably involves wrapping the connection in a net.Conn of your own devising.

Brad Fitzpatrick

unread,
Mar 20, 2012, 1:20:40 PM3/20/12
to Kyle Lemons, Sanjay Menakuru, golan...@googlegroups.com
Let's always _a_ solution, but likely not the best one.

Sanjay, could you flie a bug so I remember to look into this at some point?

Sanjay Menakuru

unread,
Mar 21, 2012, 2:41:41 AM3/21/12
to golan...@googlegroups.com, Kyle Lemons, Sanjay Menakuru
I thought of returning my own net.Conn, but its hard to tell when you're on boundaries of requests, short of actually parsing stuff. I could parse, I suppose, but the redundant work would be annoying. Its probably easier to copy the code from net/http and add a Timeout field (of type time.Duration) to Transport that sets that as the ReadDeadline after calling req.Write.

Sanjay

Johann Höchtl

unread,
Mar 21, 2012, 8:37:51 AM3/21/12
to golan...@googlegroups.com, Kyle Lemons, Sanjay Menakuru


Am Dienstag, 20. März 2012 18:20:40 UTC+1 schrieb Brad Fitzpatrick:
Let's always _a_ solution, but likely not the best one.

Sanjay, could you flie a bug so I remember to look into this at some point?


Has the former solution been a security issue for GAE? Otherwise why not restore it, provided more sensible tailoring.
 

Sean Talts

unread,
Apr 24, 2014, 5:55:16 PM4/24/14
to golan...@googlegroups.com, Kyle Lemons, Sanjay Menakuru
Here's what I've come up with, with tests: http://gist.github.com/seantalts/11266762

Involves making your own Transport and overriding RoundTrip with a function that sets a goroutine that calls the original RoundTrip and selects between that and a timeout. This is the technique they seem to use internally to set a timeout for other things in transport.go. Please let me know if I'm overlooking something or this is not good style; for example I'm aware that the goroutines will only exit once they have finished waiting for the response.

ivan.v...@gmail.com

unread,
May 3, 2014, 8:42:49 AM5/3/14
to golan...@googlegroups.com, Kyle Lemons, Sanjay Menakuru
I have a post request which uploads a video file to drive using a long running PUT request.
In your solution the request will be broken after the timeout, instead I would like to break it and create new one to continue uploading if there was no bytes sent during certain time.

Sean Talts

unread,
May 3, 2014, 9:09:24 PM5/3/14
to ivan.v...@gmail.com, golang-nuts, Kyle Lemons, Sanjay Menakuru
Good point. I think even the new http.Client Timeout in 1.3 will have the same issue, if I'm reading this right: https://codereview.appspot.com/70120045/patch/120001/130001

Doesn't affect us at the moment but good to keep track of this behavior.


--
You received this message because you are subscribed to a topic in the Google Groups "golang-nuts" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/golang-nuts/-DE6-aLttM4/unsubscribe.
To unsubscribe from this group and all its topics, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Camilo Aguilar

unread,
Aug 2, 2014, 10:24:27 AM8/2/14
to golan...@googlegroups.com, kev...@google.com, balas...@gmail.com, ivan.v...@gmail.com
I'm have exactly the same issue using http.Client to download a big file. Timeout just fires up ignoring the ongoing transfer. I'm using Go 1.3, this used to work fine using conn.SetDeadline in Go 1.2.1. The issue happens as well when setting the Timeout property in http.Client.

Camilo Aguilar

unread,
Aug 2, 2014, 10:45:02 AM8/2/14
to golan...@googlegroups.com, ivan.v...@gmail.com, kev...@google.com, balas...@gmail.com, sean....@gmail.com
I just filed a bug to track this in https://code.google.com/p/go/issues/detail?id=8465

James Bardin

unread,
Aug 2, 2014, 11:21:06 AM8/2/14
to golan...@googlegroups.com
Both methods of timing out have nothing to do with if there is activity on the connection or not. They are doing what they are supposed to do, hitting a deadline or closing the connection after the specified time.

If this worked before, it was a bug.

Camilo Aguilar

unread,
Aug 2, 2014, 12:10:28 PM8/2/14
to golan...@googlegroups.com
That makes no sense to me, would you please elaborate more? If I'm setting a timeout in the http.Client, as a user, I'm expecting it to kick in if the connection is unable to be established for some reason, ie: DNS taking too long to resolve or server taking to long to accept the connection. I wouldn't expect it to kick in in the middle of a data transfer.

James Bardin

unread,
Aug 2, 2014, 2:28:54 PM8/2/14
to Camilo Aguilar, golan...@googlegroups.com

On Sat, Aug 2, 2014 at 12:10 PM, Camilo Aguilar <camilo....@gmail.com> wrote:
>
> That makes no sense to me, would you please elaborate more? If I'm setting a timeout in the http.Client, as a user, I'm expecting it to kick in if the connection is unable to be established for some reason, ie: DNS taking too long to resolve or server taking to long to accept the connection. I wouldn't expect it to kick in in the middle of a data transfer.


The http client documentation is pretty clear with "and will interrupt reading of the Response.Body."

        // Timeout specifies a time limit for requests made by this
        // Client. The timeout includes connection time, any
        // redirects, and reading the response body. The timer remains
        // running after Get, Head, Post, or Do return and will
        // interrupt reading of the Response.Body.


As is net.Conn

        // A deadline is an absolute time after which I/O operations
        // fail with a timeout (see type Error) instead of
        // blocking. The deadline applies to all future I/O, not just
        // the immediately following call to Read or Write.


The proper way to implement an idle timeout is to walk a deadline forward on each read or write operation. If you're looking for an IdleTimeout, you need to create your own net.Conn which sets deadlines on each operation. You can look at how we implemented the ReadWriteTimeout in github.com/mreiferson/go-httpclient (which is mostly surpassed by go1.3 except for this situation).

Camilo Aguilar

unread,
Aug 2, 2014, 2:55:52 PM8/2/14
to golan...@googlegroups.com, camilo....@gmail.com
Thanks for clarifying. IMHO, just because the documentation explains the behavior doesn't mean Go's API in this regard is totally unexpected. I will be very useful to understand the reasoning behind this implementation, especially in http.Client.

James Bardin

unread,
Aug 2, 2014, 3:09:18 PM8/2/14
to Camilo Aguilar, golan...@googlegroups.com

On Sat, Aug 2, 2014 at 2:55 PM, Camilo Aguilar <camilo....@gmail.com> wrote:
I will be very useful to understand the reasoning behind this implementation, especially in http.Client.

I'm not certain I understand; are you looking for more clarification on this? If so, what aspect of it don't you understand?

Camilo Aguilar

unread,
Aug 2, 2014, 3:38:59 PM8/2/14
to golan...@googlegroups.com, camilo....@gmail.com
I'm understand now, I'm just saying it is a weird and unexpected API behavior in http.Client, despite being documented.
Reply all
Reply to author
Forward
0 new messages