python - library - Establecer el tiempo de espera para xmlrpclib.ServerProxy
xml rpc library python (10)
Estoy usando xmlrpclib.ServerProxy para hacer llamadas RPC a un servidor remoto. Si no hay una conexión de red al servidor, demora los 10 segundos predeterminados para devolver un socket.gaierror a mi programa.
Esto es molesto cuando se hace un desarrollo sin una conexión de red, o si el servidor remoto está inactivo. ¿Hay alguna manera de actualizar el tiempo de espera en mi objeto ServerProxy?
No veo una forma clara de acceder al socket para actualizarlo.
Una solución más directa es en: 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
Basado en el de antonylesuisse, una versión de trabajo (en 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)
He analizado varias formas de resolver este problema y, de lejos, la más elegante se describe aquí: https://seattle.cs.washington.edu/browser/seattle/trunk/demokit/timeout_xmlrpclib.py?rev=692
La técnica se presentó originalmente aquí, pero este enlace está muerto: http://blog.bjola.ca/2007/08/using-timeout-with-xmlrpclib.html
Esto funciona con Python 2.5 y 2.6. El nuevo enlace afirma que también funciona con Python 3.0.
Aquí hay un código que funciona en Python 2.7 (probablemente para otras versiones 2.x de Python) sin generar AttributeError, la instancia no tiene el atributo ''getresponse'' .
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=socket._GLOBAL_DEFAULT_TIMEOUT, *args, **kwargs):
xmlrpclib.Transport.__init__(self, *args, **kwargs)
self.timeout = timeout
def make_connection(self, host):
if self._connection and host == self._connection[0]:
return self._connection[1]
chost, self._extra_headers, x509 = self.get_host_info(host)
self._connection = host, httplib.HTTPConnection(chost)
return self._connection[1]
transport = TimeoutTransport(timeout=timeout)
xmlrpclib.ServerProxy.__init__(self, uri, transport=transport, allow_none=True)
Aquí hay una copia literal de http://code.activestate.com/recipes/473878/
def timeout(func, args=(), kwargs={}, timeout_duration=1, default=None):
import threading
class InterruptableThread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.result = None
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 default
else:
return it.result
Aquí otra solución inteligente y muy pitónica usando Python''s with
declaración:
import socket
import xmlrpc.client
class MyServerProxy:
def __init__(self, url, timeout=None):
self.__url = url
self.__timeout = timeout
self.__prevDefaultTimeout = None
def __enter__(self):
try:
if self.__timeout:
self.__prevDefaultTimeout = socket.getdefaulttimeout()
socket.setdefaulttimeout(self.__timeout)
proxy = xmlrpc.client.ServerProxy(self.__url, allow_none=True)
except Exception as ex:
raise Exception("Unable create XMLRPC-proxy for url ''%s'': %s" % (self.__url, ex))
return proxy
def __exit__(self, type, value, traceback):
if self.__prevDefaultTimeout is None:
socket.setdefaulttimeout(self.__prevDefaultTimeout)
Esta clase se puede usar así:
with MyServerProxy(''http://1.2.3.4'', 20) as proxy:
proxy.dummy()
Basado en el de antonylesuisse, pero funciona en Python 2.7.5, resolviendo el problema: la AttributeError: TimeoutHTTP instance has no attribute ''getresponse''
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))
def getresponse(self, *args, **kw):
return self._conn.getresponse(*args, **kw)
class TimeoutTransport(xmlrpclib.Transport):
def __init__(self, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, *l, **kw):
xmlrpclib.Transport.__init__(self, *l, **kw)
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, *l, **kw):
kw[''transport'']=TimeoutTransport(timeout=timeout, use_datetime=kw.get(''use_datetime'',0))
xmlrpclib.ServerProxy.__init__(self, uri, *l, **kw)
proxy = TimeoutServerProxy(''http://127.0.0.1:1989'', timeout=30)
print proxy.test_connection()
El siguiente ejemplo funciona con Python 2.7.4.
import xmlrpclib
from xmlrpclib import *
import httplib
def Server(url, *args, **kwargs):
t = TimeoutTransport(kwargs.get(''timeout'', 20))
if ''timeout'' in kwargs:
del kwargs[''timeout'']
kwargs[''transport''] = t
server = xmlrpclib.Server(url, *args, **kwargs)
return server
TimeoutServerProxy = Server
class TimeoutTransport(xmlrpclib.Transport):
def __init__(self, timeout, use_datetime=0):
self.timeout = timeout
return xmlrpclib.Transport.__init__(self, use_datetime)
def make_connection(self, host):
conn = xmlrpclib.Transport.make_connection(self, host)
conn.timeout = self.timeout
return connrpclib.Server(url, *args, **kwargs)
Quería una versión pequeña, limpia, pero también explícita, por lo que basándome en todas las otras respuestas aquí, esto es lo que se me ocurrió:
import xmlrpclib
class TimeoutTransport(xmlrpclib.Transport):
def __init__(self, timeout, use_datetime=0):
self.timeout = timeout
# xmlrpclib uses old-style classes so we cannot use super()
xmlrpclib.Transport.__init__(self, use_datetime)
def make_connection(self, host):
connection = xmlrpclib.Transport.make_connection(self, host)
connection.timeout = self.timeout
return connection
class TimeoutServerProxy(xmlrpclib.ServerProxy):
def __init__(self, uri, timeout=10, transport=None, encoding=None, verbose=0, allow_none=0, use_datetime=0):
t = TimeoutTransport(timeout)
xmlrpclib.ServerProxy.__init__(self, uri, t, encoding, verbose, allow_none, use_datetime)
proxy = TimeoutServerProxy(some_url)
Al principio, no me di cuenta de que xmlrpclib
tiene clases antiguas, por lo que me pareció útil hacer un comentario al respecto, de lo contrario, todo debería ser bastante fácil de explicar.
No veo por qué httplib.HTTP
tendría que ser subclasificado también, si alguien puede aclararme sobre esto, por favor hazlo. La solución anterior se prueba y funciona.
limpiar la versión no global.
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()