pyro4: Create pyro proxy factory which returns instaces scoped by the request.

This commit is contained in:
Martin Bornhold 2016-07-04 16:35:03 +02:00
parent 81fbfe0335
commit 20205cf371
2 changed files with 53 additions and 10 deletions

View file

@ -64,11 +64,11 @@ def connect_pyro4(server_and_port):
from rhodecode.lib.vcs import connection, client
from rhodecode.lib.middleware.utils import scm_app
git_remote = client.ThreadlocalProxyFactory(
git_remote = client.RequestScopeProxyFactory(
settings.pyro_remote(settings.PYRO_GIT, server_and_port))
hg_remote = client.ThreadlocalProxyFactory(
hg_remote = client.RequestScopeProxyFactory(
settings.pyro_remote(settings.PYRO_HG, server_and_port))
svn_remote = client.ThreadlocalProxyFactory(
svn_remote = client.RequestScopeProxyFactory(
settings.pyro_remote(settings.PYRO_SVN, server_and_port))
connection.Git = client.RepoMaker(proxy_factory=git_remote)

View file

@ -34,6 +34,7 @@ from urllib2 import URLError
import msgpack
import Pyro4
import requests
from pyramid.threadlocal import get_current_request
from Pyro4.errors import CommunicationError, ConnectionClosedError, DaemonError
from rhodecode.lib.vcs import exceptions
@ -190,19 +191,61 @@ class RepoMaker(object):
return _wrap_remote_call(remote_proxy, func)
class ThreadlocalProxyFactory(object):
class RequestScopeProxyFactory(object):
"""
Creates one Pyro4 proxy per thread on demand.
This factory returns pyro proxy instances based on a per request scope.
It returns the same instance if called from within the same request and
different instances if called from different requests.
"""
def __init__(self, remote_uri):
self._remote_uri = remote_uri
self._thread_local = threading.local()
self._proxy_pool = []
self._borrowed_proxies = {}
def __call__(self):
if not hasattr(self._thread_local, 'proxy'):
self._thread_local.proxy = Pyro4.Proxy(self._remote_uri)
return self._thread_local.proxy
def __call__(self, request=None):
"""
Wrapper around `getProxy`.
"""
request = request or get_current_request()
return self.getProxy(request)
def getProxy(self, request=None):
"""
Call this to get the pyro proxy instance for the request.
"""
request = request or get_current_request()
# Return already borrowed proxy for this request
if request in self._borrowed_proxies:
return self._borrowed_proxies[request]
# Get proxy from pool or create new instance.
try:
proxy = self._proxy_pool.pop()
except IndexError:
log.info('Creating new proxy for remote_uri=%s', self._remote_uri)
proxy = Pyro4.Proxy(self._remote_uri)
# Store proxy instance as borrowed and add request callback.
self._borrowed_proxies[request] = proxy
request.add_finished_callback(self._returnProxy)
return proxy
def _returnProxy(self, request=None):
"""
Callback that gets called by pyramid when the request is finished.
It puts the proxy back into the pool.
"""
request = request or get_current_request()
if request in self._borrowed_proxies:
proxy = self._borrowed_proxies.pop(request)
self._proxy_pool.append(proxy)
else:
log.warn('Return proxy for remote_uri=%s but no proxy borrowed '
'for this request.', self._remote_uri)
class RemoteRepo(object):