Установить тайм-аут для xmlrpclib.ServerProxy
Я использую xmlrpclib.ServerProxy для вызова RPC на удаленный сервер. Если нет сетевого подключения к серверу, он принимает 10 секунд по умолчанию для возврата socket.gaierror в мою программу.
Это раздражает при разработке без сетевого подключения или если удаленный сервер не работает. Есть ли способ обновить тайм-аут на моем объекте ServerProxy?
Я не вижу ясного способа получить доступ к сокету для его обновления.
Ответы
Ответ 1
Более простое решение:
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
Ответ 2
чистая не глобальная версия.
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()
Ответ 3
Я рассмотрел несколько способов решения этой проблемы и, безусловно, самый элегантный из них описан здесь:
https://seattle.cs.washington.edu/browser/seattle/trunk/demokit/timeout_xmlrpclib.py?rev=692
Техника изначально была представлена здесь, но эта ссылка мертва:
http://blog.bjola.ca/2007/08/using-timeout-with-xmlrpclib.html
Это работает с Python 2.5 и 2.6. Новая ссылка также претендует на работу с Python 3.0.
Ответ 4
Вот код, который работает на Python 2.7 (возможно, для других версий 2.x Python) без повышения AttributeError, экземпляр не имеет атрибута 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)
Ответ 5
Мне нужна небольшая, чистая, но явная версия, поэтому на основе всех других ответов здесь я пришел к следующему:
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)
Я не понимал, что сначала xmlrpclib
имеет классы старого стиля, поэтому я нашел его полезным с комментарием по этому поводу, в противном случае все должно быть довольно понятным.
Я не понимаю, почему httplib.HTTP
должен быть также подклассифицирован, если кто-то может просветить меня по этому поводу, пожалуйста. Вышеупомянутое решение проверено и работает.
Ответ 6
Вот стенографическая копия 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
Ответ 7
Основываясь на одном из antonylesuisse, рабочая версия (на 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)
Ответ 8
Здесь другое умное и очень pythonic решение с использованием инструкции Python with
:
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)
Этот класс можно использовать следующим образом:
with MyServerProxy('http://1.2.3.4', 20) as proxy:
proxy.dummy()
Ответ 9
Следующий пример работает с 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)
Ответ 10
На основе одного из antonylesuisse, но работает на Python 2.7.5, разрешая проблему: 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()