def setUp(self) -> None: fp = open(os.path.join(__location__, "workflow_started_decision_task_response.json")) self.poll_response: PollForDecisionTaskResponse = json_to_data_class(json.loads(fp.read()), PollForDecisionTaskResponse) fp.close() self.worker = Worker() self.loop = DecisionTaskLoop(worker=self.worker) global dummy_workflow_self dummy_workflow_self = None
def test_worker_register_query_method(): worker = Worker() worker.register_workflow_implementation_type(DummyWorkflowImpl, "DummyWorkflow") assert DummyWorkflowImpl._query_methods assert "DummyWorkflow::dummy_query" in DummyWorkflowImpl._query_methods assert "DummyWorkflow::dummyQuery" in DummyWorkflowImpl._query_methods assert "DummyWorkflow::dummy_query_paren" in DummyWorkflowImpl._query_methods assert "DummyWorkflow::dummyQueryParen" in DummyWorkflowImpl._query_methods assert "blah" in DummyWorkflowImpl._query_methods
def new_worker(self, task_list: str, worker_options: WorkerOptions = None) -> Worker: worker = Worker(host=self.host, port=self.port, domain=self.domain, task_list=task_list, options=worker_options) self.workers.append(worker) return worker
class TestDecisionTaskLoop(TestCase): def setUp(self) -> None: fp = open( os.path.join(__location__, "workflow_started_decision_task_response.json")) self.poll_response: PollForDecisionTaskResponse = json_to_data_class( json.loads(fp.read()), PollForDecisionTaskResponse) fp.close() self.worker = Worker() self.loop = DecisionTaskLoop(worker=self.worker) global dummy_workflow_self dummy_workflow_self = None def test_create_workflow_object(self): class DummyWorkflow: @workflow_method() async def dummy(self): nonlocal dummy_workflow_self dummy_workflow_self = self dummy_workflow_self = None self.worker.register_workflow_implementation_type(DummyWorkflow) self.loop.process_task(self.poll_response) self.assertIsInstance(dummy_workflow_self, DummyWorkflow) def test_return_none(self): class DummyWorkflow: @workflow_method() async def dummy(self): return None self.worker.register_workflow_implementation_type(DummyWorkflow) decisions = self.loop.process_task(self.poll_response) complete_workflow = decisions[ 0].complete_workflow_execution_decision_attributes self.assertEqual("null", complete_workflow.result) def test_one_arg(self): class DummyWorkflow: @workflow_method() async def dummy(self, arg1): nonlocal arg1_value arg1_value = arg1 arg1_value = None self.worker.register_workflow_implementation_type(DummyWorkflow) self.poll_response.history.events[ 0].workflow_execution_started_event_attributes.input = json.dumps( ["first"]) self.loop.process_task(self.poll_response) self.assertEqual(arg1_value, "first") def test_args(self): class DummyWorkflow: @workflow_method() async def dummy(self, arg1, arg2): nonlocal arg1_value, arg2_value arg1_value = arg1 arg2_value = arg2 arg1_value = None arg2_value = None self.worker.register_workflow_implementation_type(DummyWorkflow) self.poll_response.history.events[ 0].workflow_execution_started_event_attributes.input = json.dumps( ["first", "second"]) self.loop.process_task(self.poll_response) self.assertEqual(arg1_value, "first") self.assertEqual(arg2_value, "second") def test_no_args(self): class DummyWorkflow: @workflow_method() async def dummy(self): nonlocal executed executed = True executed = False self.worker.register_workflow_implementation_type(DummyWorkflow) self.poll_response.history.events[ 0].workflow_execution_started_event_attributes.input = json.dumps( []) self.loop.process_task(self.poll_response) self.assertTrue(executed) def test_return_value(self): class DummyWorkflow: @workflow_method() async def dummy(self): return "value" self.worker.register_workflow_implementation_type(DummyWorkflow) decisions = self.loop.process_task(self.poll_response) complete_workflow = decisions[ 0].complete_workflow_execution_decision_attributes self.assertEqual('"value"', complete_workflow.result)
def activity_task_loop(worker: Worker): service: WorkflowService = WorkflowService.create( worker.host, worker.port, timeout=worker.get_timeout()) worker.manage_service(service) logger.info( f"Activity task worker started: {WorkflowService.get_identity()}") try: while True: if worker.is_stop_requested(): return try: service.set_next_timeout_cb(worker.raise_if_stop_requested) polling_start = datetime.datetime.now() polling_request = PollForActivityTaskRequest() polling_request.task_list_metadata = TaskListMetadata() polling_request.task_list_metadata.max_tasks_per_second = 200000 polling_request.domain = worker.domain polling_request.identity = WorkflowService.get_identity() polling_request.task_list = TaskList() polling_request.task_list.name = worker.task_list task: PollForActivityTaskResponse task, err = service.poll_for_activity_task(polling_request) polling_end = datetime.datetime.now() logger.debug("PollForActivityTask: %dms", (polling_end - polling_start).total_seconds() * 1000) except StopRequestedException: return except Exception as ex: logger.error("PollForActivityTask error: %s", ex) continue if err: logger.error("PollForActivityTask failed: %s", err) continue task_token = task.task_token if not task_token: logger.debug( "PollForActivityTask has no task_token (expected): %s", task) continue args = json_to_args(task.input) logger.info(f"Request for activity: {task.activity_type.name}") fn = worker.activities.get(task.activity_type.name) if not fn: logger.error("Activity type not found: " + task.activity_type.name) continue process_start = datetime.datetime.now() activity_context = ActivityContext() activity_context.service = service activity_context.activity_task = ActivityTask.from_poll_for_activity_task_response( task) activity_context.domain = worker.domain try: ActivityContext.set(activity_context) return_value = fn(*args) if activity_context.do_not_complete: logger.info( f"Not completing activity {task.activity_type.name}({str(args)[1:-1]})" ) continue error = complete(service, task_token, return_value) if error: logger.error( "Error invoking RespondActivityTaskCompleted: %s", error) logger.info( f"Activity {task.activity_type.name}({str(args)[1:-1]}) returned {json.dumps(return_value)}" ) except Exception as ex: logger.error( f"Activity {task.activity_type.name} failed: {type(ex).__name__}({ex})", exc_info=1) error = complete_exceptionally(service, task_token, ex) if error: logger.error( "Error invoking RespondActivityTaskFailed: %s", error) finally: ActivityContext.set(None) process_end = datetime.datetime.now() logger.info("Process ActivityTask: %dms", (process_end - process_start).total_seconds() * 1000) finally: try: service.close() except: logger.warning("service.close() failed", exc_info=1) worker.notify_thread_stopped()
def setUpClass(cls) -> None: cls.task_list = "task-list-" + str(uuid4()) cls.worker = worker = Worker("localhost", 7933, "test-domain", cls.task_list) worker.register_workflow_implementation_type(GreetingWorkflow) worker.start()
def worker(): return Worker()
def activity_task_loop(worker: Worker): service = WorkflowService.create(worker.host, worker.port) logger.info( f"Activity task worker started: {WorkflowService.get_identity()}") try: while True: if worker.is_stop_requested(): return try: polling_start = datetime.datetime.now() polling_request = PollForActivityTaskRequest() polling_request.task_list_metadata = TaskListMetadata() polling_request.task_list_metadata.max_tasks_per_second = 200000 polling_request.domain = worker.domain polling_request.identity = WorkflowService.get_identity() polling_request.task_list = TaskList() polling_request.task_list.name = worker.task_list task: PollForActivityTaskResponse task, err = service.poll_for_activity_task(polling_request) polling_end = datetime.datetime.now() logger.debug("PollForActivityTask: %dms", (polling_end - polling_start).total_seconds() * 1000) except Exception as ex: logger.error("PollForActivityTask error: %s", ex) continue if err: logger.error("PollForActivityTask failed: %s", err) continue if not task.task_token: logger.debug( "PollForActivityTask has no task_token (expected): %s", task) continue args = json_to_args(task.input) logger.info(f"Request for activity: {task.activity_type.name}") fn = worker.activities.get(task.activity_type.name) if not fn: logger.error("Activity type not found: " + task.activity_type.name) continue process_start = datetime.datetime.now() activity_context = ActivityContext() activity_context.task_token = task.task_token activity_context.workflow_execution = task.workflow_execution activity_context.domain = worker.domain try: ActivityContext.set(activity_context) ret = fn(*args) ActivityContext.set(None) respond = RespondActivityTaskCompletedRequest() respond.task_token = task.task_token respond.result = json.dumps(ret) respond.identity = WorkflowService.get_identity() _, error = service.respond_activity_task_completed(respond) if error: logger.error( "Error invoking RespondActivityTaskCompleted: %s", error) logger.info( f"Activity {task.activity_type.name}({str(args)[1:-1]}) returned {respond.result}" ) except Exception as ex: logger.error( f"Activity {task.activity_type.name} failed: {type(ex).__name__}({ex})", exc_info=1) respond: RespondActivityTaskFailedRequest = RespondActivityTaskFailedRequest( ) respond.task_token = task.task_token respond.identity = WorkflowService.get_identity() respond.details = json.dumps({ "detailMessage": f"Python error: {type(ex).__name__}({ex})", "class": "java.lang.Exception" }) respond.reason = "java.lang.Exception" _, error = service.respond_activity_task_failed(respond) if error: logger.error( "Error invoking RespondActivityTaskFailed: %s", error) process_end = datetime.datetime.now() logger.info("Process ActivityTask: %dms", (process_end - process_start).total_seconds() * 1000) finally: worker.notify_thread_stopped()
def worker(): worker = Worker() worker.register_workflow_implementation_type(DummyWorkflow) return worker
def worker(): worker = Worker() return worker