def test_broker_smoke():
    with Broker('localhost') as client:
        client.connect()
        client.setup_exchange()
        client.declare(output_queue=task_input_queue)
        logger.info('Sending task')
        for i in test_tasks:
            client.push(test_tasks[i])
    with Broker('localhost') as agent:
        agent.connect()
        agent.declare(input_queue=task_input_queue,
                      output_queue=task_result_queue)
        agent._inactivity_timeout = 0.1
        logger.info('Processing task')
        for task in agent.pulling_generator():
            result = process_task(task)
            agent.set_task_done(task)
            agent.push(result)
    with Broker('localhost') as validator:
        validator.connect()
        validator.declare(input_queue=task_result_queue)
        validator._inactivity_timeout = 0.1
        logger.info('Validating results')
        for task in validator.pulling_generator():
            validator_callback(task)
            validator.set_task_done(task)
Exemple #2
0
class Client:
    def __init__(self,
                 name: str,
                 token: str,
                 dsp_ip: str = 'localhost',
                 dsp_port: int = 9999):
        logger.info('Starting Client')
        self.name = name
        self.token = token
        self.socket = RequestConnection(dsp_ip, dsp_port)
        self.broker = None

    def __enter__(self):
        self.socket.establish()
        return self

    def __exit__(self, *exc_info):
        self.socket.close()

    def get_client_queues(self):
        request = deepcopy(Client_queues)
        request['name'] = self.name
        request['token'] = self.token
        reply = self.socket.send(request)
        if reply['result']:
            self.broker = Broker(reply['broker']['host'])
            self.broker.connect()
            self.broker.declare(reply['broker']['result'],
                                reply['broker']['task'])
        else:
            ConnectionRefusedError('Invalid credentials or resource is busy')
Exemple #3
0
 def __init__(self,
              ip: str = '*',
              port: Union[int, str] = '',
              broker_host: str = ''):
     logger.info('Starting Dispatcher')
     self.socket = ReplyConnection(ip, port)
     self.broker = Broker(broker_host if broker_host else ip)
     self.agents = {}
     self.request_handler = self.default_request_handler
     self._next_free_id = INIT_AGENT_ID
     self._listen = True
     self._interrupt: Union[None, Callable] = None
Exemple #4
0
 def get_client_queues(self):
     request = deepcopy(Client_queues)
     request['name'] = self.name
     request['token'] = self.token
     reply = self.socket.send(request)
     if reply['result']:
         self.broker = Broker(reply['broker']['host'])
         self.broker.connect()
         self.broker.declare(reply['broker']['result'],
                             reply['broker']['task'])
     else:
         ConnectionRefusedError('Invalid credentials or resource is busy')
Exemple #5
0
 def init_broker(self):
     """
     Request Agent queues on Broker from Dispatcher.
     """
     request = deepcopy(Agent_queues)
     request['token'] = self.token
     request['id'] = self.id
     reply = self.socket.send(request)
     if reply['result']:
         self.sync(reply)
         self.broker = Broker(reply['broker']['host'])
         self.broker.connect()
         self.broker.declare(reply['broker']['task'],
                             reply['broker']['result'])
Exemple #6
0
def broker():
    host = '*'
    with Broker(host) as broker:
        broker.connect()
        # broker._interrupt = polling_expiration
        broker._inactivity_timeout = 0.1 * SECOND
        broker.declare(input_queue=task_queue,
                       output_queue=compose_queue(RoutingKeys.RESULTS))
        yield broker
        input_queue = broker.input_queue
    flush_queue(host, input_queue)
Exemple #7
0
def flush_queue(broker: str,
                queue: dict = task_queue,
                assert_non_empty: bool = True):
    with Broker(broker) as br:
        br.connect()
        br.declare(queue)
        br._inactivity_timeout = 0.1  # seconds
        empty = True
        logger.info(f'Flushing queue: {queue}')
        for task in br.pulling_generator():
            empty = False
            br.set_task_done(task)
        if assert_non_empty:
            assert empty, f'Flushed queue {queue} is not empty'
Exemple #8
0
def test_agent_queues(agent_on_dispatcher: Agent, broker: Broker):
    agent = agent_on_dispatcher
    test_task = deepcopy(task_body)
    test_task['arguments'] = 'agent_task_test'
    task_result = deepcopy(task_body)
    task_result['arguments'] = 'agent_task_result'
    broker.declare(input_queue=compose_queue(RoutingKeys.RESULTS),
                   output_queue=compose_queue(RoutingKeys.TASK))
    broker.push(test_task)
    task = next(agent.broker.pulling_generator())
    agent.broker.set_task_done(task)
    assert test_task == task.body, \
        'Wrong task is received from task queue for Agent'
    agent.broker.push(task_result)
    result = next(broker.pulling_generator())
    broker.set_task_done(result)
    assert task_result == result.body, \
        'Wrong Agent result is received from task queue'
Exemple #9
0
class Agent(AgentBase):
    def __init__(self,
                 token: str,
                 dsp_host: str = 'localhost',
                 dsp_port: int = 9999):
        logger.info('Starting Agent')
        super(Agent, self).__init__()
        self.socket = RequestConnection(dsp_host, dsp_port)
        self.broker = None
        self.token = token

    def __enter__(self):
        self.socket.establish()
        return self

    def __exit__(self, *exc_info):
        self.close()

    def close(self):
        if self.broker:
            self.broker.close()
        self.socket.close()

    def register(self):
        request = deepcopy(Register_agent)
        if self.name:
            request['name'] = self.name
        request['token'] = self.token
        reply = self.socket.send(request)
        if reply['result']:
            self.id = reply['id']
            self.sync(reply)
        return reply['result']

    def init_broker(self):
        """
        Request Agent queues on Broker from Dispatcher.
        """
        request = deepcopy(Agent_queues)
        request['token'] = self.token
        request['id'] = self.id
        reply = self.socket.send(request)
        if reply['result']:
            self.sync(reply)
            self.broker = Broker(reply['broker']['host'])
            self.broker.connect()
            self.broker.declare(reply['broker']['task'],
                                reply['broker']['result'])

    def pulse(self) -> bool:
        request = deepcopy(Pulse)
        request['id'] = self.id
        reply = self.socket.send(request)
        self.sync(reply['reply'])
        return reply['result']

    def sync(self, reply: dict):
        self.last_sync = datetime.utcnow()
        if 'commands' in reply:
            self.commands = reply['commands']

    def apply_commands(self):
        for command in self.commands:
            _method = getattr(self, command)
            if not _method():
                logger.error(f'Method "{_method}" has failed to apply')
                return False
        else:
            return True

    def disconnect(self):
        request = deepcopy(Disconnect)
        request['id'] = self.id
        reply = self.socket.send(request)
        if reply['result']:
            self.broker.close()
            self.broker = None
            self.id = 0
        return reply['result']

    def shutdown(self):
        self.__exit__()
        exit(0)
Exemple #10
0
class Dispatcher:
    def __init__(self,
                 ip: str = '*',
                 port: Union[int, str] = '',
                 broker_host: str = ''):
        logger.info('Starting Dispatcher')
        self.socket = ReplyConnection(ip, port)
        self.broker = Broker(broker_host if broker_host else ip)
        self.agents = {}
        self.request_handler = self.default_request_handler
        self._next_free_id = INIT_AGENT_ID
        self._listen = True
        self._interrupt: Union[None, Callable] = None

    def __enter__(self):
        self.socket.establish()
        self.configure_broker()
        return self

    def __exit__(self, *exc_info):
        logger.info(f'Closing Dispatcher connection:{self.socket}')
        self.socket.close()
        self.broker.close()

    def configure_broker(self):
        self.broker._inactivity_timeout = 0.01 * SECOND
        if self.broker.connect() and not self.broker.input_queue:
            self.broker.setup_exchange()
            self.broker.declare(
                input_queue=compose_queue(RoutingKeys.DISPATCHER))

    def listen(self, polling_timeout: int = 10 * SECOND):
        while self._listen:
            expired = self.socket.listen(self.request_handler, polling_timeout)
            if self._interrupt and self._interrupt(expired):
                break
            if not self.broker.input_queue and not self.broker.channel.is_open:
                self.configure_broker()
            else:
                for task in self.broker.pulling_generator():
                    logger.debug(f'Got dispatcher task {task}')

    def default_request_handler(self, request: dict):
        commands = {
            Commands.Register_agent: self._register_agent_handler,
            Commands.Agent_queues: self._agent_queues_handler,
            Commands.Pulse: self._pulse_handler,
            Commands.Client_queues: self._client_handler,
            Commands.Relay: self._relay,
            Commands.Disconnect: self._disconnect_handler
        }
        assert request['command'] in commands, 'Command ' \
            f'{request["command"]} is not registered in dispatcher request handler'
        command = commands[request['command']]
        return command(request)

    def _register_agent_handler(self, request: dict):
        logger.info(
            f'Registration request received {request["name"]}({self._next_free_id})'
        )
        request['id'] = self._next_free_id
        agent = RemoteAgent(self._next_free_id)
        agent.name = request['name']
        agent.token = request['token']
        self.agents[self._next_free_id] = agent
        logger.info(f'New agent id={agent.id}')
        request['result'] = True
        self._next_free_id += 1
        return request

    def _agent_queues_handler(self, request: dict):
        """
        Returns Host and queues that agent should connect to.
        """
        agent = self.agents[request['id']]
        logger.info(f'Agent queues request received from {agent}')
        config = Database.get_agent_param(agent.token)
        request['broker']['host'] = config['broker']
        request['broker']['task'] = compose_queue(RoutingKeys.TASK)
        request['broker']['result'] = compose_queue(RoutingKeys.RESULTS)
        request['result'] = True
        return request

    def _pulse_handler(self, request: dict):
        logger.info(f'Pulse request received {request["id"]}')
        agent = self.agents[request['id']]
        reply = agent.sync(request)
        return reply

    def _client_handler(self, request: dict):
        logger.info(f'Client queues are requested by: {request["name"]}')
        config = Database.get_client_param(request['token'])
        request['broker']['host'] = config['broker']
        request['broker']['task'] = compose_queue(RoutingKeys.TASK)
        request['broker']['result'] = compose_queue(request['name'])
        request['result'] = True
        return request

    def _disconnect_handler(self, request: dict):
        """
        Removes agent instance on dispatcher.
        """
        logger.info(f'Disconnect request received {request["id"]}')
        if request['id'] in self.agents:
            self.agents.pop(request['id'])
        request['result'] = True
        return request

    def _relay(self, request: dict):
        """
        Returns received request.
        """
        logger.debug(f'Relay request called')
        return request