getaddrinfo in a thread



  • DNS lookups via 4G on a GPY can take up to 20s if things don't go well

    import time, usocket, _thread
    def _dns(host, port):
      ai = usocket.getaddrinfo(host, port); ai=ai[0]; return ai
    
    start=time.time()
    ai=_dns('some url', 443)
    stop=time.time(); wait=stop-start; print('wait =', wait, ' dns =', ai)
    

    for example, returns

    wait = 14  dns = (2, 1, 0, '', ('0.0.0.0', 443))
    

    Since we can't wait that long in a battery powered GPY we tried a thread

    import time, usocket, _thread
    def _dns(host, port):
      global ai; ai=usocket.getaddrinfo(host, port); ai=ai[0]
    
    start=time.time(); ai=0
    _thread.start_new_thread(_dns, ('some url', 443))
    for i in range(5):
      print(i, ai), time.sleep(1)
      if ai: break
    stop=time.time(); wait=stop-start; print('wait =', wait, ' dns =', ai)
    

    more or less the same result

    0 0
    wait = 13  dns = (2, 1, 0, '', ('0.0.0.0', 443))
    

    We don't get it. Why doesn't the main program timeout after 5s? Why does it pause after the first iteration of the loop & wait for the thread? Isn't the idea of a thread that it allows the main program to continue regardless of what the thread is doing?



  • Just retyped this for the sake of improved readability. You might want to save it as /flash/lib/dnstest.py.

    import time
    import usocket
    import machine
    import _thread
    """
    >>> import dnstest; dnstest.dns_lookup('google.com')
    0 None
    1 (2, 1, 0, '', ('172.217.18.14', 443))
    2 (2, 1, 0, '', ('172.217.18.14', 443))
    3 (2, 1, 0, '', ('172.217.18.14', 443))
    4 (2, 1, 0, '', ('172.217.18.14', 443))
    """
    
    response = None
    
    
    def run_getaddrinfo(host, port):
        global response
        response = usocket.getaddrinfo(host, port)[0]
    
    
    def dns_lookup(hostname, timeout=5):
    
        _thread.start_new_thread(run_getaddrinfo, (hostname, 443))
    
        for i in range(timeout):
            print(i, response)
            machine.idle()
            time.sleep(1)
    
        print('Ready.')
    

    It works flawlessly over a WiFi connection, but LTE might well have its delicacies.



  • What should print(i, ai), time.sleep(1) actually do? I believe your thread might crash without notice.

    @andreas said in urequests timeouts:

    I can't decipher your code

    However, you might want to add machine.idle() while you are waiting for the thread outcome in order to feed the OS scheduler.



  • getaddrinfo does not only have issues on MicroPython when used in a thread [1]. These things are tricky.

    [1] https://emptysqua.re/blog/getaddrinfo-deadlock/



  • This post is deleted!


  • Is this guy for real?!



  • @kjm GPY works with the 5G LTE CAT M1 and NB-Iot. You need to buy a 5G sim card from a service provider and follow the examples found on our website: CAT M1 and NB-Iot


Log in to reply
 

Pycom on Twitter