def test_cast_calls_basic_publish_with_correct_rk(self, conn): a = A(conn) exch = a.type_to_exchange[ACTOR_TYPE.DIRECT]().name a = A(conn) rk = a.routing_key self.assert_cast_calls_basic_publish_with(a, rk, exch, None) agent = Mock(id=uuid()) a = A(conn, agent=agent) rk = a.routing_key self.assertNotEqual(a.routing_key, agent.id) self.assert_cast_calls_basic_publish_with(a, rk, exch, None) agent = Mock(id=uuid()) id = '1234' a = A(conn, agent=agent, id=id) rk = a.routing_key self.assertEqual(a.routing_key, id) self.assert_cast_calls_basic_publish_with(a, rk, exch, None) self.assertEquals(a.routing_key, rk) self.assert_cast_calls_basic_publish_with(a, rk, exch, None) a = A(conn) a.default_routing_key = 'fooooooooo' rk = a.default_routing_key self.assertEquals(a.routing_key, rk) self.assert_cast_calls_basic_publish_with(a, rk, exch, None)
def test_on_message_is_sending_to_reply_queue(self, conn): ret_result = 'foooo' class Foo(A): class state: def bar(self, my_bar): return ret_result a = Foo(conn) ticket = uuid() delivery_tag = uuid() body, message = get_encoded_test_message('bar', {'my_bar': 'bar_arg'}, A.__class__.__name__, reply_to=ticket, delivery_tag=delivery_tag) # Set up a reply queue to read from # reply_q and reply_exchange should be set the sender a.reply_exchange = a.reply_exchange.bind(a.connection.default_channel) maybe_declare(a.reply_exchange) reply_q = a.get_reply_queue(ticket) reply_q(a.connection.default_channel).declare() a._on_message(body, message) a_con = Consumer(conn.channel(), reply_q) self.assertNextMsgDataEqual(a_con, {'ok': ret_result})
def _prepare_client_queue(self, command_name): """Setup a client queue based on the command. """ if self._client_queue is None: corr_uuid = uuid() self._client_queue = '.'.join([command_name, 'client', corr_uuid])
def call(self, method, args={}, retry=False, retry_policy=None, ticket=None, **props): """Send message to the same actor and return :class:`AsyncResult`.""" ticket = ticket or uuid() reply_q = self.get_reply_queue(ticket) self.cast(method, args, declare=[reply_q], reply_to=ticket, **props) return self.AsyncResult(ticket, self)
def prepare(self, *, exchange=None, routing_key=None, reply_to=None, correlation_id=None, json=None, persistent=True, **kwargs): message_id = uuid() if reply_to is not None: if isinstance(reply_to, Queue): reply_to = reply_to.name if reply_to == self.reply_queue.name and correlation_id is None: correlation_id = message_id kwargs['exchange'] = exchange if exchange is not None else '' kwargs['routing_key'] = routing_key if routing_key is not None else '' kwargs['reply_to'] = reply_to kwargs['app_id'] = self.app_id kwargs['message_id'] = message_id kwargs['correlation_id'] = correlation_id kwargs['delivery_mode'] = 2 if persistent else 1 if json is not None: if callable(json): json = json() kwargs['serializer'] = 'json' kwargs['body'] = json else: kwargs.setdefault('body', '') return kwargs
def spawn(self, cls, kwargs={}, nowait=False): """Spawn a new actor on a celery worker by sending a remote command to the worker. :param cls: the name of the :class:`~.cell.actors.Actor` class or its derivative. :keyword kwargs: The keyword arguments to pass on to actor __init__ (a :class:`dict`) :keyword nowait: If set to True (default) the call waits for the result of spawning the actor. if False, the spawning is asynchronous. :returns :class:`~.cell.actors.ActorProxy`:, holding the id of the spawned actor. """ actor_id = uuid() if str(qualname(cls)) == '__builtin__.unicode': name = cls else: name = qualname(cls) res = self.call('spawn', {'cls': name, 'id': actor_id, 'kwargs': kwargs}, type=ACTOR_TYPE.RR, nowait=nowait) return ActorProxy(name, actor_id, res, agent=self, connection=self.connection, **kwargs)
def __init__(self, connection=None, id=None, name=None, exchange=None, logger=None, agent=None, **kwargs): self.connection = connection self.id = id or uuid() self.name = name or self.name or self.__class__.__name__ self.exchange = exchange or self.exchange self.agent = agent if not self.exchange: self.exchange = Exchange('cl.%s' % (self.name, ), 'direct') type_map = {ACT_TYPE.DIRECT: [self.get_direct_queue, self._inbox_direct], ACT_TYPE.RR: [self.get_rr_queue, self._inbox_rr], ACT_TYPE.SCATTER: [self.get_scatter_queue, self._inbox_scatter]} self.type_to_queue = {k: v[0] for k, v in type_map.iteritems()} self.type_to_exchange = {k: v[1] for k, v in type_map.iteritems()} if self.default_fields is None: self.default_fields = {} if not self.output_exchange: self.output_exchange = Exchange('cl.%s.output' % (self.name), 'topic') logger_name = self.name if self.agent: logger_name = '%s#%s' % (self.name, shortuuid(self.agent.id, )) self.log = Log('!<%s>' % (logger_name, ), logger=logger) self.state = self.contribute_to_state(self.construct_state()) self.setup()
def __init__(self, connection=None, id=None, name=None, exchange=None, logger=None, agent=None, **kwargs): self.connection = connection self.id = id or uuid() self.name = name or self.name or self.__class__.__name__ self.exchange = exchange or self.exchange self.agent = agent self.type_to_queue = { 'direct': self.get_direct_queue, 'round-robin': self.get_rr_queue, 'scatter': self.get_scatter_queue } if self.default_fields is None: self.default_fields = {} if not self.exchange: self.exchange = Exchange('cl.%s' % (self.name, ), 'direct', auto_delete=True) logger_name = self.name if self.agent: logger_name = '%s#%s' % (self.name, shortuuid(self.agent.id, )) self.log = Log('!<%s>' % (logger_name, ), logger=logger) self.state = self.contribute_to_state(self.construct_state()) self.setup()
def add(self, name=None, app=None, nowait=False, **kwargs): if nowait: name = name if name else uuid() ret = self.throw('add', dict({'name': name, 'app': app}, **kwargs), nowait=nowait) if nowait: return {'name': name} return ret
def test_bind_with_agent(self): """test when Actor.bind(connection, agent)""" a = A() agent = Mock(id=uuid()) with Connection('memory://') as conn: bound = a.bind(conn, agent=agent) self.assertIs(bound.agent, agent) self.assertIs(bound.state.agent, agent)
def add(self, name=None, app=None, nowait=False, **kwargs): if nowait: name = name if name else uuid() ret = self.throw("add", dict({"name": name, "app": app}, **kwargs), nowait=nowait) if nowait: return {"name": name} return ret
def call(self, method, args={}, retry=False, retry_policy=None, **props): """Send message to actor and return :class:`AsyncResult`.""" ticket = uuid() reply_q = self.get_reply_queue(ticket) def before(connection, channel): reply_q(channel).declare() self.cast(method, args, before, **dict(props, reply_to=ticket)) return self.AsyncResult(ticket, self)
def test_arbitrary_actor_method(self, meth): a1 = ActorProxy(qualname(As), uuid()) a1.meth() meth.assert_called_once_with() meth.reset_mock() args = ['bar'] a1.meth(*args) meth.assert_called_once_with(*args)
def get_test_message(method='foo', args={'bar': 'foo_arg'}, class_name=None, reply_to=None, delivery_tag=None): with Connection('memory://') as conn: ch = conn.channel() body = {'method': method, 'args': args, 'class': class_name} data = ch.prepare_message(body) data['properties']['reply_to'] = reply_to delivery_tag = delivery_tag or uuid() data['properties']['delivery_tag'] = delivery_tag return body, ch.message_to_python(data)
def __init__(self, connection=None, id=None, name=None, exchange=None, logger=None, agent=None, outbox_exchange=None, group_exchange=None, **kwargs): self.connection = connection self.id = id or uuid() self.name = name or self.name or self.__class__.__name__ self.outbox_exchange = outbox_exchange or self.outbox_exchange self.agent = agent if self.default_fields is None: self.default_fields = {} # - setup exchanges and queues self.exchange = exchange or self.get_direct_exchange() if group_exchange: self._scatter_exchange = Exchange(group_exchange, 'fanout', auto_delete=True) typemap = { ACTOR_TYPE.DIRECT: [self.get_direct_queue, self._inbox_direct], ACTOR_TYPE.RR: [self.get_rr_queue, self._inbox_rr], ACTOR_TYPE.SCATTER: [self.get_scatter_queue, self._inbox_scatter] } self.type_to_queue = {k: v[0] for k, v in items(typemap)} self.type_to_exchange = {k: v[1] for k, v in items(typemap)} if not self.outbox_exchange: self.outbox_exchange = Exchange( 'cl.%s.output' % self.name, type='topic', ) # - setup logging logger_name = self.name if self.agent: logger_name = '%s#%s' % (self.name, shortuuid(self.id)) self.log = Log('!<%s>' % logger_name, logger=logger) self.state = self.contribute_to_state(self.construct_state()) # actor specific initialization. self.construct()
def get_encoded_test_message(method='foo', args={'bar': 'foo_arg'}, class_name=A.__class__.__name__, reply_to=None, delivery_tag=None): with Connection('memory://') as conn: ch = conn.channel() body = {'method': method, 'args': args, 'class': class_name} c_body, compression = compress(str(body), 'gzip') data = ch.prepare_message(c_body, content_type='application/json', content_encoding='utf-8', headers={'compression': compression}) data['properties']['reply_to'] = reply_to delivery_tag = delivery_tag or uuid() data['properties']['delivery_tag'] = delivery_tag return body, ch.message_to_python(data)
def test_on_message_invokes_on_dispatch_when_reply_to_set(self): ret_val = 'fooo' ticket = uuid() body, message = get_test_message('foo', {'bar': 'foo_arg'}, A.__class__.__name__, reply_to=ticket) a = A() a.reply = Mock() a._DISPATCH = Mock(return_value=ret_val) # when reply_to is set: # dispatch result should be ignored a._on_message(body, message) a._DISPATCH.assert_called_once_with(body, ticket=ticket) a.reply.assert_called_once_with(message, ret_val)
def rpc(self, command_name, data=None, server_routing_key=None): """Send a RPC request :command_name: the command to execute (used as routing key) :data: dict with data to be sent :client_queue: Queue for this particular request :server_routing_key: Server routing key. Will default to <command>.server """ self.reply_received = False payload = self._setup_payload(command_name, data) logger.info("Preparing request {!r}".format(payload)) if server_routing_key is None: if self._prefix is None: server_routing_key = command_name else: server_routing_key = '.'.join([self._prefix, command_name]) self._prepare_client_queue(command_name) logger.info("Set up client queue {!r} " "to {!r}".format(self._client_queue, server_routing_key)) message_correlation_id = uuid() properties = { 'reply_to': self._client_queue, 'correlation_id': message_correlation_id } self.corr_id_server_queue[message_correlation_id] = server_routing_key logger.info('STARTREQUEST:%s;CORRELATION_ID:%s' % (server_routing_key, message_correlation_id)) result = None try: self.messages[message_correlation_id] = True self._send_command(payload, server_routing_key, properties) result = self.retrieve_messages() except Exception: logger.error("Sending message to consumer queue failed.", exc_info=True) raise # Successful so store message correlation id for retrieval. return result
def test_reply_queue_is_declared_after_call(self, conn): ticket = uuid() with patch('cell.actors.uuid') as new_uuid: new_uuid.return_value = ticket a = A(conn) reply_q = a.get_reply_queue(ticket) a.get_reply_queue = Mock(return_value=reply_q) with self.assertRaises(ChannelError): reply_q(conn.channel()).queue_declare(passive=True) a.call(method='foo', args={}, type=ACTOR_TYPE.DIRECT) a.get_reply_queue.assert_called_once_with(ticket) self.assertTrue( reply_q(conn.channel()).queue_declare(passive=True))
def assert_cast_calls_basic_publish_with(self, a, routing_key, exchange, type, mocked_publish): method, args = 'foo', {'bar': 'foo_arg'} type = type or ACTOR_TYPE.DIRECT ticket = uuid() expected_body, _ = get_test_message( method, args, a.__class__.__name__, reply_to=ticket) a.cast(method, args, type=type) mocked_publish.assert_called_once_with( ANY, immediate=ANY, mandatory=ANY, exchange=exchange, routing_key=routing_key) (message, ), _ = mocked_publish.call_args body = ast.literal_eval(message.get('body')) self.assertDictEqual(body, expected_body)
def assert_cast_calls_basic_publish_with(self, a, routing_key, exchange, type, mocked_publish): method, args = 'foo', {'bar': 'foo_arg'} type = type or ACTOR_TYPE.DIRECT ticket = uuid() expected_body, _ = get_test_message(method, args, a.__class__.__name__, reply_to=ticket) a.cast(method, args, type=type) mocked_publish.assert_called_once_with(ANY, immediate=ANY, mandatory=ANY, exchange=exchange, routing_key=routing_key) (message, ), _ = mocked_publish.call_args body = ast.literal_eval(message.get('body')) self.assertDictEqual(body, expected_body)
def __init__(self, connection=None, id=None, name=None, exchange=None, logger=None, agent=None, **kwargs): self.connection = connection self.id = id or uuid() self.name = name or self.name or self.__class__.__name__ self.exchange = exchange or self.exchange self.agent = agent self.type_to_queue = {'direct': self.get_direct_queue, 'round-robin': self.get_rr_queue, 'scatter': self.get_scatter_queue} if self.default_fields is None: self.default_fields = {} if not self.exchange: self.exchange = Exchange('cl.%s' % (self.name, ), 'direct', auto_delete=True) logger_name = self.name if self.agent: logger_name = '%s#%s' % (self.name, shortuuid(self.agent.id, )) self.log = Log('!<%s>' % (logger_name, ), logger=logger) self.state = self.contribute_to_state(self.construct_state()) self.setup()
def __init__(self, connection=None, id=None, name=None, exchange=None, logger=None, agent=None, outbox_exchange=None, group_exchange=None, **kwargs): self.connection = connection self.id = id or uuid() self.name = name or self.name or self.__class__.__name__ self.outbox_exchange = outbox_exchange or self.outbox_exchange self.agent = agent if self.default_fields is None: self.default_fields = {} # - setup exchanges and queues self.exchange = exchange or self.get_direct_exchange() if group_exchange: self._scatter_exchange = Exchange( group_exchange, 'fanout', auto_delete=True) typemap = { ACTOR_TYPE.DIRECT: [self.get_direct_queue, self._inbox_direct], ACTOR_TYPE.RR: [self.get_rr_queue, self._inbox_rr], ACTOR_TYPE.SCATTER: [self.get_scatter_queue, self._inbox_scatter] } self.type_to_queue = {k: v[0] for k, v in items(typemap)} self.type_to_exchange = {k: v[1] for k, v in items(typemap)} if not self.outbox_exchange: self.outbox_exchange = Exchange( 'cl.%s.output' % self.name, type='topic', ) # - setup logging logger_name = self.name if self.agent: logger_name = '%s#%s' % (self.name, shortuuid(self.id)) self.log = Log('!<%s>' % logger_name, logger=logger) self.state = self.contribute_to_state(self.construct_state()) # actor specific initialization. self.construct()
def test_reply_send_correct_msg_body_to_the_reply_queue(self, conn): a = A(conn) ticket = uuid() delivery_tag = 2 body, message = get_encoded_test_message('bar', {'my_bar': 'bar_arg'}, a.__class__.__name__, reply_to=ticket, delivery_tag=delivery_tag) # Set up a reply queue to read from # reply_q and reply_exchange should be set the sender a.reply_exchange.maybe_bind(a.connection.default_channel) maybe_declare(a.reply_exchange) reply_q = a.get_reply_queue(ticket) reply_q(a.connection.default_channel).declare() a.reply(message, body) a_con = Consumer(conn.channel(), reply_q) reply_msg = get_next_msg(a_con) reply_body = reply_msg.decode() self.assertEquals(reply_body, body)
def spawn(self, cls, kwargs={}, nowait=False): """Spawn a new actor on a celery worker by sending a remote command to the worker. :param cls: the name of the :class:`~.cell.actors.Actor` class or its derivative. :keyword kwargs: The keyword arguments to pass on to actor __init__ (a :class:`dict`) :keyword nowait: If set to True (default) the call waits for the result of spawning the actor. if False, the spawning is asynchronous. :returns :class:`~.cell.actors.ActorProxy`:, holding the id of the spawned actor. """ actor_id = uuid() if str(qualname(cls)) == '__builtin__.unicode': name = cls else: name = qualname(cls) res = self.call('spawn', { 'cls': name, 'id': actor_id, 'kwargs': kwargs }, type=ACTOR_TYPE.RR, nowait=nowait) return ActorProxy(name, actor_id, res, agent=self, connection=self.connection, **kwargs)
def test_on_message_when_reply_to_is_set(self): class Foo(Actor): class state(): foo_called = False def foo(self, bar): self.foo_called = True return (bar, ret_val) args, ret_val = {'bar': 'foo_arg'}, 'foooo' ticket = uuid() body, message = get_test_message( 'foo', args, Foo.__class__.__name__, reply_to=[ticket]) a = Foo() a.reply = Mock() # when the property reply_to is set, reply is called a._on_message(body, message) self.assertTrue(a.state.foo_called) a.reply.assert_called_oncce()
def test_init(self, conn): """test that __init__ sets fields""" id = uuid() ag, res = Mock(), Mock() # we need to have wait for result, a1 = ActorProxy(qualname(A), id, connection=conn, agent=ag) self.assertEqual(a1.id, id) self.assertIsNone(a1.async_start_result) self.assertIsInstance(a1._actor, A) self.assertEqual(a1._actor.name, A().__class__.__name__) self.assertEqual(a1._actor.agent, ag) self.assertEqual(a1._actor.id, a1.id) self.assertEqual(a1._actor.connection, conn) a1 = ActorProxy(qualname(A), id, res, connection=conn, agent=ag) self.assertEqual(a1.id, id) self.assertEqual(a1.async_start_result, res) self.assertEqual(a1._actor.id, a1.id) self.assertIsInstance(a1._actor, A) self.assertEqual(a1._actor.name, A().__class__.__name__) self.assertEqual(a1._actor.agent, ag) self.assertEqual(a1._actor.connection, conn)
def test_on_message_when_reply_to_is_set(self): class Foo(Actor): class state(): foo_called = False def foo(self, bar): self.foo_called = True return (bar, ret_val) args, ret_val = {'bar': 'foo_arg'}, 'foooo' ticket = uuid() body, message = get_test_message('foo', args, Foo.__class__.__name__, reply_to=[ticket]) a = Foo() a.reply = Mock() # when the property reply_to is set, reply is called a._on_message(body, message) self.assertTrue(a.state.foo_called) a.reply.assert_called_oncce()
def test_call(self, call): a1 = ActorProxy(qualname(As), uuid()) self.assert_actor_method_called(call, a1.call)
def test_send(self, send): a1 = ActorProxy(qualname(As), uuid()) self.assert_actor_method_called(send, a1.send)
def test_scatter(self, scatter): a1 = ActorProxy(qualname(As), uuid()) self.assert_actor_method_called(scatter, a1.scatter)
def test_send_dot(self, send): a1 = ActorProxy(qualname(As), uuid()) self.assert_actor_method_called_with_par_foo(send, a1.send)
def test_throw(self, throw): a1 = ActorProxy(qualname(As), uuid()) self.assert_actor_method_called(throw, a1.throw)
def test_non_existing_actor_method(self): a1 = ActorProxy(qualname(As), uuid()) with self.assertRaises(AttributeError): a1.bar()
def test_throw_dot(self, throw): a1 = ActorProxy(qualname(As), uuid()) self.assert_actor_method_called_with_par_foo(throw, a1.throw)
def test_scatter_dot(self, scatter): a1 = ActorProxy(qualname(As), uuid()) self.assert_actor_method_called_with_par_foo(scatter, a1.scatter)
def __init__(self, connection, id=None, actors=None): self.connection = connection self.id = id or uuid() if actors is not None: self.actors = actors self.actors = self.prepare_actors()