def acquire_lock(name, expiry=None, context=None, conn=None): """ Acquire a lock in redis. :param str name: Name of the lock to acquire :param int expiry: The duration of the lock (in seconds) :param str context: The context to apply to the lock name :param redis.Connection conn: The redis connection to use :rtype: :class:`bool` :returns: Whether or not the lock was acquired """ # pylint: disable=W0212 current = time() lock_expiry = 3 if expiry is None else expiry lock_expires = current + lock_expiry lock_context = 'global.lock' if context is None else context lock_name = '%s:%s' % (lock_context, name) redis = get_redis_connection() if conn is None else conn # try to get lock; if we fail, do sanity check on lock if not redis.setnx(lock_name, lock_expires): # see if current lock is expired; if so, take it if current < float(redis.get(lock_name)): # lock is not expired return False elif current < float(redis.getset(lock_name, lock_expires)): # somebody else beat us to it return False # we have the lock; give it a TTL and pass through redis.expire(lock_name, lock_expiry) return True
def __init__(self, uuid=None): """ Initialize the Actor object. :param str uuid: Optionally-provided UUID """ atexit.register(self.__del__) self._stop = Event() #: Separate Thread for handling messages self._proc = None #: Redis connection self._redis = get_redis_connection() # pylint: disable=E1123 self._pubsub = self._redis.pubsub(ignore_subscribe_messages=True) if uuid: self.uuid = uuid else: self.uuid = str(uuid4()) if not REGISTRY.exists(self.uuid): REGISTRY.register(self.uuid) else: self.uuid = None raise UUIDInUseException('UUID is already taken')
def acquire_lock(name, expiry=None, context=None, conn=None): """ Acquire a lock in redis. :param str name: Name of the lock to acquire :param int expiry: The duration of the lock (in seconds) :param str context: The context to apply to the lock name :param redis.Connection conn: The redis connection to use :rtype: :class:`bool` :returns: Whether or not the lock was acquired """ # pylint: disable=W0212 current = time() lock_expiry = 3 if expiry is None else expiry lock_expires = current + lock_expiry lock_context = 'global.lock' if context is None else context lock_name = '%s:%s' % (lock_context, name) redis = get_redis_connection() if conn is None else conn # try to get lock; if we fail, do sanity check on lock if not redis.setnx(lock_name, lock_expires): # see if current lock is expired; if so, take it if (current < float(redis.get(lock_name)) or current < float(redis.getset(lock_name, lock_expires))): # lock is not expired or somebody else beat us to it return False # we have the lock; give it a TTL and pass through redis.expire(lock_name, lock_expiry) return True
def __init__(self, prefix=None): """ Initialize the registry. :param str prefix: Optional prefix for redis key names """ self._redis = get_redis_connection() self._list = '{prefix}actors'.format(prefix=prefix)
def __init__(self, channel): """ Initialize instance of ClusterProxy. :param str channel: The cluster channel to use """ #: Cluster channel self.channel = channel #: Redis connection self._redis = get_redis_connection() #: Redis PubSub client self._pubsub = None #: This proxy object's UUID for creating unique channels self.proxyid = str(uuid4()) #: Response queues for sandboxing method calls self._response_queues = {} #: Response counters for the response queue self._response_counters = {} self._stop = Event() # pylint: disable=E1123 self._pubsub = self._redis.pubsub(ignore_subscribe_messages=True) self._pubsub.subscribe(**{'proxy:%s' % self.proxyid: self._handler}) def pubsub_thread(): """ Call get_message in loop to fire _handler. """ try: while not self._stop.is_set(): self._pubsub.get_message() sleep(0.001) except: # pylint: disable=W0702 pass # fire up the message handler thread as a daemon proc = Thread(target=pubsub_thread) proc.daemon = True proc.start()
def __init__(self, actor=None, uuid=None): """ Initialize instance of ActorProxy. Accepts either an Actor object to clone or a UUID, but not both. :param rodario.actors.Actor actor: Actor to clone :param str uuid: UUID of Actor to clone """ #: Redis connection self._redis = get_redis_connection() #: Redis PubSub client self._pubsub = None #: This proxy object's UUID for creating unique channels self.proxyid = str(uuid4()) #: Response queues for sandboxing method calls self._response_queues = {} # avoid cyclic import actor_module = __import__('rodario.actors', fromlist=('Actor', )) # pylint: disable=E1123 self._pubsub = self._redis.pubsub(ignore_subscribe_messages=True) self._pubsub.subscribe(**{'proxy:%s' % self.proxyid: self._handler}) methods = set() def pubsub_thread(): """ Call get_message in loop to fire _handler. """ try: while self._pubsub: self._pubsub.get_message() sleep(0.001) except: # pylint: disable=W0702 pass # fire up the message handler thread as a daemon proc = Thread(target=pubsub_thread) proc.daemon = True proc.start() if isinstance(actor, actor_module.Actor): # proxying an Actor directly self.uuid = actor.uuid methods = actor._get_methods() # pylint: disable=W0212 elif isinstance(uuid, str): # proxying by UUID; get actor methods over pubsub self.uuid = uuid methods = self._proxy('_get_methods').get() else: raise InvalidProxyException('No actor or UUID provided') def get_lambda(name): """ Generate a lambda function to proxy the given method. :param str name: Name of the method to proxy :rtype: :expression:`lambda` """ return lambda _, *args, **kwargs: self._proxy( name, *args, **kwargs) # create proxy methods for each public method of the original Actor for name in methods: setattr(self, name, types.MethodType(get_lambda(name), self))
def __init__(self, actor=None, uuid=None): """ Initialize instance of ActorProxy. Accepts either an Actor object to clone or a UUID, but not both. :param rodario.actors.Actor actor: Actor to clone :param str uuid: UUID of Actor to clone """ #: Redis connection self._redis = get_redis_connection() #: Redis PubSub client self._pubsub = None #: This proxy object's UUID for creating unique channels self.proxyid = str(uuid4()) #: Response queues for sandboxing method calls self._response_queues = {} # avoid cyclic import actor_module = __import__('rodario.actors', fromlist=('Actor',)) # pylint: disable=E1123 self._pubsub = self._redis.pubsub(ignore_subscribe_messages=True) self._pubsub.subscribe(**{'proxy:%s' % self.proxyid: self._handler}) methods = set() def pubsub_thread(): """ Call get_message in loop to fire _handler. """ try: while self._pubsub: self._pubsub.get_message() sleep(0.001) except: # pylint: disable=W0702 pass # fire up the message handler thread as a daemon proc = Thread(target=pubsub_thread) proc.daemon = True proc.start() if isinstance(actor, actor_module.Actor): # proxying an Actor directly self.uuid = actor.uuid methods = actor._get_methods() # pylint: disable=W0212 elif isinstance(uuid, str): # proxying by UUID; get actor methods over pubsub self.uuid = uuid methods = self._proxy('_get_methods').get() else: raise InvalidProxyException('No actor or UUID provided') def get_lambda(name): """ Generate a lambda function to proxy the given method. :param str name: Name of the method to proxy :rtype: :expression:`lambda` """ return lambda _, *args, **kwargs: self._proxy(name, *args, **kwargs) # create proxy methods for each public method of the original Actor for name in methods: setattr(self, name, types.MethodType(get_lambda(name), self))