This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: set a timeout for DNS lookups
Type: enhancement Stage: resolved
Components: Library (Lib) Versions: Python 3.5
process
Status: closed Resolution: rejected
Dependencies: Superseder:
Assigned To: Nosy List: kevinburke, piotr.dobrogost, r.david.murray
Priority: normal Keywords:

Created on 2014-11-17 05:38 by kevinburke, last changed 2022-04-11 14:58 by admin. This issue is now closed.

Messages (4)
msg231266 - (view) Author: Kevin Burke (kevinburke) Date: 2014-11-17 05:38
It would be nice to be able to set a timeout for DNS lookups in the event of a DNS server failure.

1. Set your DNS to something like 123.123.123.123 or any other host that is not listening for DNS queries on port 53.

2. Run requests.get('http://jsonip.com', timeout=3), or similar using urllib/http.client/httplib

3. Observe that the wall clock time is 2 minutes or higher.

It's known that a timeout value does not correspond to wall clock time, but this can be an unexpected cause of latency in http client requests, and is completely uncontrollable from client code (unless the user resolves DNS themselves). 

For a comparison, Go provides this functionality, see for example https://code.google.com/p/go/source/browse/src/pkg/net/lookup.go?name=release#55
msg231273 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2014-11-17 08:42
As far as I know, the libc dns timeout is controlled by /etc/resolv.conf (or whatever the Windows equivalent is), and libc doesn't provide any way for an application to override this.  There is no mention of timeout on the resolver(3) man page.   Do you know of a way?  (One that doesn't change global state.)  (In theory one could re-implement a DNS resolver client, but that is not something CPython is going to do :)
msg231290 - (view) Author: Kevin Burke (kevinburke) Date: 2014-11-17 17:58
Hi,
You are correct, there's no way to set it in the C API. Go works around this by resolving addresses in a goroutine. I was wondering if something similar would be possible in Python (for people who set a timeout in the interface).
msg231291 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2014-11-17 18:54
Oh, my apologies.  I totally missed your link to the go example when I first read your message.

Yes, Python supports the equivalent.  In the asyncio module, which is our closest equivalent to goroutines, the functionality exists implicitly: the base event loop has a getaddrinfo coroutine that is used for DNS lookup, and it is run in a separate thread to keep from blocking the event loop.  If you time out (wait_for with a timeout) a coroutine that ends up doing a DNS request, your wait_for call will time out whether or not the getaddrinfo DNS lookup has timed out.

Using asyncio isn't quite as simple as prefixing a function name with 'go', but it isn't all that hard, either.  Nevertheless, if you aren't using asyncio for the rest of your program, it probably makes more sense to write a function that launches a thread to do the getaddrinfo and does a wait on the thread with a timeout.  (But you might want to check out if asyncio applies to your overall problem.)

So yes, Python can do this, but I don't think it makes sense to build it in to the stdlib's socket module (say), since unlike go async and threading aren't part of the core language but are instead libraries themselves.  asyncio already has it built in.  For the thread based version, putting a recipe on one of the recipe sites might be good, if there isn't one already.
History
Date User Action Args
2022-04-11 14:58:10adminsetgithub: 67078
2015-01-23 10:27:32piotr.dobrogostsetnosy: + piotr.dobrogost
2014-11-17 18:54:09r.david.murraysetstatus: open -> closed
resolution: rejected
messages: + msg231291

stage: resolved
2014-11-17 17:58:53kevinburkesetmessages: + msg231290
2014-11-17 08:42:36r.david.murraysetnosy: + r.david.murray
messages: + msg231273
2014-11-17 05:38:20kevinburkecreate