class Agent(object): """Agent class presents an instance of agent application.""" def __init__(self, afm_url, default_wait=60, max_tasks=2, name="Python Agent 1.0", agent_uuid=None): """ Initialize Agent object. :param afm_url: The URL for the AFM service. :param default_wait: Amount of time to wait after each run iteration. :param max_tasks: Maximum tasks this agent can execute during one run iteration. :param name: The name of this Agent instance. :param agent_uuid: UUID for this Agent instance. """ self.afm = Communicator(afm_url) self.max_tasks = max_tasks self.default_wait = default_wait self.name = name self.uuid = agent_uuid if agent_uuid else str(uuid.uuid1()) self._run = True logging.basicConfig(format="%(asctime)s - %(name)s - %(levelname)s - %(message).120s") def exit(self): """ Signal agent to exit. After issuing exit, agent will not make further task requests, but will wait until all currently processed tasks finish. """ self._run = False def run(self): """The "main function" of the agent, looping the claim & execute tasks flow.""" with Executor(self.max_tasks) as executor: while self._run: wait_time = self.default_wait min_wait_time = 1 # request for tasks try: task_response = self.afm.request_tasks( agent_id=self.uuid, agent_name=self.name, agent_time=timeutil.format(timeutil.now()), agent_capabilities=TaskHandler.list_all(), max_tasks=executor.available_executors(), ) if "tasks" in task_response: for task_data in task_response["tasks"]: executor.submit_task( task_data, lambda *args, **kwargs: self.afm.post_result(*args, **kwargs) ) if "return_time" in task_response: return_time = timeutil.parse(task_response["return_time"]) wait_time = max(min_wait_time, (return_time - timeutil.now()).total_seconds()) except TemporaryError as e: logging.getLogger("Agent").error("An error occurred while claiming tasks: %s", e) time.sleep(wait_time)
class Agent(object): """ Agent class presents an instance of agent application. """ def __init__(self, afm_url, default_wait=60, max_tasks=2, name='Python Agent 1.0', agent_uuid=None): self.afm = Communicator(afm_url) self.max_tasks = max_tasks self.default_wait = default_wait self.name = name self.uuid = agent_uuid if agent_uuid else str(uuid.uuid1()) self._run = True def exit(self): """ Signal agent to exit. After issuing exit, agent will not make further task requests, but will wait until all currently processed tasks finish. """ self._run = False def run(self): """ The "main function" of the agent, looping the claim & execute tasks flow. """ with Executor(self.max_tasks) as executor: while self._run: wait_time = self.default_wait min_wait_time = 1 # request for tasks try: task_response = self.afm.request_tasks( agent_id=self.uuid, agent_name=self.name, agent_time=timeutil.format(timeutil.now()), agent_capabilities=TaskHandler.list_all(), max_tasks=executor.available_executors() ) if 'tasks' in task_response: for task_data in task_response['tasks']: executor.submit_task(task_data, lambda *args, **kwargs: self.afm.post_result(*args, **kwargs)) if 'return_time' in task_response: return_time = timeutil.parse(task_response['return_time']) wait_time = max(min_wait_time, (return_time - timeutil.now()).total_seconds()) except TemporaryError as e: logging.getLogger("Agent").error("An error occurred while claiming tasks: %s", e) time.sleep(wait_time)
def __init__(self, afm_url, default_wait=60, max_tasks=2, name='Python Agent 1.0', agent_uuid=None): self.afm = Communicator(afm_url) self.max_tasks = max_tasks self.default_wait = default_wait self.name = name self.uuid = agent_uuid if agent_uuid else str(uuid.uuid1()) self._run = True
def __init__(self, afm_url, default_wait=60, max_tasks=2, name="Python Agent 1.0", agent_uuid=None): """ Initialize Agent object. :param afm_url: The URL for the AFM service. :param default_wait: Amount of time to wait after each run iteration. :param max_tasks: Maximum tasks this agent can execute during one run iteration. :param name: The name of this Agent instance. :param agent_uuid: UUID for this Agent instance. """ self.afm = Communicator(afm_url) self.max_tasks = max_tasks self.default_wait = default_wait self.name = name self.uuid = agent_uuid if agent_uuid else str(uuid.uuid1()) self._run = True logging.basicConfig(format="%(asctime)s - %(name)s - %(levelname)s - %(message).120s")
def setUp(self): self.communicator = Communicator('https://localhost')
class CommunicatorTests(unittest.TestCase): def setUp(self): self.communicator = Communicator('https://localhost') @responses.activate def test_server_error(self): _add_responses(status=500) with self.assertRaises(TemporaryError): self.communicator.request_tasks() @responses.activate def test_client_error(self): _add_responses(status=400) with self.assertRaises(FatalError): self.communicator.request_tasks() @responses.activate def test_json_error(self): _add_responses(body="[asd") with self.assertRaises(FatalError): self.communicator.request_tasks() @responses.activate def test_connection_error(self): _add_responses(url='https://localhost2/tasks') with self.assertRaises(TemporaryError): self.communicator.request_tasks() @responses.activate def test_valid_json(self): _add_responses( body=json.dumps({ "tasks": [ { "task_id": "123e4567-e89b-12d3-a456-426655440000", "task_type": "wait", "task_version": 1, "task_data": { "time": "1" } } ], "return_time": "2012-04-23T18:25:43.511Z" }) ) self.assertIsInstance(self.communicator.request_tasks(), dict) @responses.activate def test_result_retries(self): class CountResponses(object): def __init__(self): self.counter = 0 def __call__(self, request): self.counter += 1 assert self.counter <= 2, 'Agent should stop retrying after OK response!' if self.counter < 2: return 500, {}, None else: return 200, {}, None responses.add_callback( responses.POST, 'https://localhost/tasks/response', callback=CountResponses(), content_type='application/json' ) self.communicator.post_result('task-id', task_data={}) self.assertEqual(len(responses.calls), 2, 'Agent should retry result upload on temporary error!')