tags:

views:

1570

answers:

5

I am using xmlrpclib.ServerProxy to make RPC calls to a remote server. If there is not a network connection to the server it takes the default 10 seconds to return a socket.gaierror to my program.

This is annoying when doing development without a network connection, or if the remote server is down. Is there a way to update the timeout on my ServerProxy object?

I can't see a clear way to get access to the socket to update it.

+4  A: 

I have looked at several ways to solve this issue and by far the most elegant is described here: http://blog.bjola.ca/2007/08/using-timeout-with-xmlrpclib.html

This works with Python 2.5 and 2.6.

Troy J. Farrell
Unfortunately that no longer works with the latest xmlrpclib as far as I can tell.
ashchristopher
Which version of Python are you using?
Troy J. Farrell
A: 

Here's a same/similar question:

http://stackoverflow.com/questions/366682/how-to-limit-execution-time-of-a-function-call-in-python

A more general solution is to use threads, where a thread is created with a time out that wraps your function. Here's the recipe from: http://code.activestate.com/recipes/473878/

def timeout(func, args=(), kwargs={}, timeout_duration=1, default=None):
    '''This function will spwan a thread and run the given function using the args, kwargs and 
    return the given default value if the timeout_duration is exceeded 
    ''' 
    import threading
    class InterruptableThread(threading.Thread):
        def __init__(self):
            threading.Thread.__init__(self)
            self.result = default
        def run(self):
            try:
                self.result = func(*args, **kwargs)
            except:
                self.result = default
    it = InterruptableThread()
    it.start()
    it.join(timeout_duration)
    if it.isAlive():
        return it.result
    else:
        return it.result
monkut
A: 

An more straightforward solution is at: http://www.devpicayune.com/entry/200609191448

import xmlrpclib 
import socket

x = xmlrpclib.ServerProxy('http:1.2.3.4')  
socket.setdefaulttimeout(10)        #set the timeout to 10 seconds 
x.func_name(args)                   #times out after 10 seconds
socket.setdefaulttimeout(None)      #sets the default back
azarias
How does the socket apply to the xmlrpclib? We are never setting the socket on x.
ashchristopher
@ashchristopher: I have not tested this code, but it looks like setdefaulttimeout is a global default value. So if xmlrpclib does not set any specific timeout value, it will probably use the global default.
MiniQuark
+2  A: 

clean non global version.

import xmlrpclib
import httplib

class TimeoutHTTPConnection(httplib.HTTPConnection):
   def connect(self):
       httplib.HTTPConnection.connect(self)
       self.sock.settimeout(self.timeout)

class TimeoutHTTP(httplib.HTTP):
   _connection_class = TimeoutHTTPConnection
   def set_timeout(self, timeout):
       self._conn.timeout = timeout

class TimeoutTransport(xmlrpclib.Transport):
    def __init__(self, timeout=10, *l, **kw):
        xmlrpclib.Transport.__init__(self,*l,**kw)
        self.timeout=timeout
    def make_connection(self, host):
        conn = TimeoutHTTP(host)
        conn.set_timeout(self.timeout)
        return conn

class TimeoutServerProxy(xmlrpclib.ServerProxy):
    def __init__(self,uri,timeout=10,*l,**kw):
        kw['transport']=TimeoutTransport(timeout=timeout, use_datetime=kw.get('use_datetime',0))
        xmlrpclib.ServerProxy.__init__(self,uri,*l,**kw)

if __name__ == "__main__":
    s=TimeoutServerProxy('http://127.0.0.1:9090',timeout=2)
    s.dummy()
antonylesuisse
Works perfectly for me, Python2.5 on Debian. BTW, you have a spurious '.' character in the imports, and 'import socket' is unused.
Tartley
A: 

Based on the one from antonylesuisse, a working version (on python >= 2.6).

# -*- coding: utf8 -*-
import xmlrpclib
import httplib
import socket

class TimeoutHTTP(httplib.HTTP):
   def __init__(self, host='', port=None, strict=None,
                timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
        if port == 0:
            port = None
        self._setup(self._connection_class(host, port, strict, timeout))

class TimeoutTransport(xmlrpclib.Transport):
    def __init__(self, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, *args, **kwargs):
        xmlrpclib.Transport.__init__(self, *args, **kwargs)
        self.timeout = timeout

    def make_connection(self, host):
        host, extra_headers, x509 = self.get_host_info(host)
        conn = TimeoutHTTP(host, timeout=self.timeout)
        return conn

class TimeoutServerProxy(xmlrpclib.ServerProxy):
    def __init__(self, uri, timeout=socket._GLOBAL_DEFAULT_TIMEOUT,
                 *args, **kwargs):
        kwargs['transport'] = TimeoutTransport(timeout=timeout,
                                    use_datetime=kwargs.get('use_datetime', 0))
        xmlrpclib.ServerProxy.__init__(self, uri, *args, **kwargs)
KangOl