def signal_external_workflow_execution(self, workflow_id, signal_name, run_id=None, control=None, input=None): """ Requests a signal to be delivered to the specified external workflow execution and records a SignalExternalWorkflowExecutionInitiated event in the history. :param str workflow_id: the id of the workflow execution to be signaled :param str signal_name: the name of the signal :param str run_id: The runId of the workflow execution to be signaled :param str control: data attached to event, used by the decider :param str input: input data to be provided with the signal """ d = { 'decisionType': 'SignalExternalWorkflowExecution', 'signalExternalWorkflowExecutionDecisionAttributes': { 'workflowId': workflow_id, 'runId': str_or_none(run_id), 'signalName': signal_name, 'input': str_or_none(input), 'control': str_or_none(control) } } normalize_data(d) self._data.append(d)
def schedule_activity_task(self, activity_id, activity_type_name, activity_type_version, task_list=None, task_priority=None, control=None, heartbeat_timeout=None, schedule_to_close_timeout=None, schedule_to_start_timeout=None, start_to_close_timeout=None, input=None): """ Schedules an activity task. :type activity_id: string :param activity_id: The activityId of the type of the activity being scheduled. :type activity_type_name: string :param activity_type_name: The name of the type of the activity being scheduled. :type activity_type_version: string|int|float :param activity_type_version: The version of the type of the activity being scheduled. :type task_list: string :param task_list: If set, specifies the name of the task list in which to schedule the activity task. If not specified, the defaultTaskList registered with the activity type will be used. Note: a task list for this activity task must be specified either as a default for the activity type or through this field. If neither this field is set nor a default task list was specified at registration time then a fault will be returned. """ d = { 'decisionType': 'ScheduleActivityTask', 'scheduleActivityTaskDecisionAttributes': { 'activityId': activity_id, 'activityType': { 'name': activity_type_name, 'version': str(activity_type_version) }, 'taskList': {'name': str_or_none(task_list)}, 'taskPriority': str_or_none(task_priority), 'control': control, 'heartbeatTimeout': duration_encode(heartbeat_timeout, 'heartbeat_timeout'), 'scheduleToCloseTimeout': duration_encode( schedule_to_close_timeout, 'schedule_to_close_timeout'), 'scheduleToStartTimeout': duration_encode( schedule_to_start_timeout, 'schedule_to_start_timeout'), 'startToCloseTimeout': duration_encode(start_to_close_timeout, 'start_to_close_timeout'), 'input': str_or_none(input) } } normalize_data(d) self._data.append(d)
def continue_as_new_workflow_execution(self, child_policy=None, execution_start_to_close_timeout=None, input=None, tag_list=None, task_list=None, task_priority=None, start_to_close_timeout=None, workflow_type_version=None, lambda_role=None): """ Closes the workflow execution and starts a new workflow execution of the same type using the same workflow id and a unique run Id. A WorkflowExecutionContinuedAsNew event is recorded in the history. """ d = { 'decisionType': 'ContinueAsNewWorkflowExecution', 'continueAsNewWorkflowExecutionDecisionAttributes': { 'input': str_or_none(input), 'executionStartToCloseTimeout': duration_encode( execution_start_to_close_timeout, 'execution_start_to_close_timeout'), 'taskList': {'name': str_or_none(task_list)}, 'taskPriority': str_or_none(task_priority), 'taskStartToCloseTimeout': duration_encode( start_to_close_timeout, 'start_to_close_timeout'), 'childPolicy': cp_encode(child_policy), 'tagList': tags_encode(tag_list), 'workflowTypeVersion': str_or_none(workflow_type_version), 'lambdaRole': str_or_none(lambda_role) } } normalize_data(d) self._data.append(d)
def start_workflow_execution(self, domain, wid, name, version, input=None, priority=None, task_list=None, execution_start_to_close_timeout=None, task_start_to_close_timeout=None, child_policy=None, tags=None, lambda_role=None): """Wrapper for `boto3.client('swf').start_workflow_execution`.""" kwargs = { 'domain': str_or_none(domain), 'workflowId': str_or_none(wid), 'workflowType': { 'name': str_or_none(name), 'version': str_or_none(version) }, 'input': str_or_none(input), 'taskPriority': str_or_none(priority), 'taskList': { 'name': str_or_none(task_list) }, 'executionStartToCloseTimeout': str_or_none(execution_start_to_close_timeout), 'taskStartToCloseTimeout': str_or_none(task_start_to_close_timeout), 'childPolicy': cp_encode(child_policy), 'tagList': tags_encode(tags), 'lambda_role': str_or_none(lambda_role) } normalize_data(kwargs) response = self.client.start_workflow_execution(**kwargs) return response
def really_start(*args, **kwargs): """Use this function to start a workflow by passing in the args.""" l1 = layer1 if layer1 is not None else Layer1() l_wid = wid # closue hack if l_wid is None: l_wid = uuid.uuid4() if serialize_input is None: input_data = Proxy.serialize_input(*args, **kwargs) else: input_data = serialize_input(*args, **kwargs) if len(input_data) > INPUT_SIZE: logger.error("Input too large: %s/%s" % (len(input_data), INPUT_SIZE)) raise ValueError('Input too large.') try: r = l1.start_workflow_execution( str(domain), str(l_wid), str(name), str(version), task_list=str_or_none(task_list), execution_start_to_close_timeout=str_or_none(workflow_duration), task_start_to_close_timeout=str_or_none(decision_duration), input=str(input_data), child_policy=cp_encode(child_policy), tag_list=tags_encode(tags)) except SWFResponseError: logger.exception('Error while starting the workflow:') raise RuntimeError('Cannot start the workflow.') return r['runId']
def respond_activity_task_completed(self, task_token, result=None): """Wrapper for `boto3.client('swf').respond_activity_task_completed`.""" kwargs = { 'taskToken': str_or_none(task_token), 'result': str_or_none(result) } normalize_data(kwargs) response = self.client.respond_activity_task_completed(**kwargs) return response
def record_activity_task_heartbeat(self, task_token, details=None): """Wrapper for `boto3.client('swf').record_activity_task_heartbeat`.""" kwargs = { 'taskToken': str_or_none(task_token), 'details': str_or_none(details), } normalize_data(kwargs) response = self.client.record_activity_task_heartbeat(**kwargs) return response
def respond_activity_task_failed(self, task_token, reason=None, details=None): """Wrapper for `boto3.client('swf').respond_activity_task_failed`.""" kwargs = { 'taskToken': str_or_none(task_token), 'reason': str_or_none(reason), 'details': str_or_none(details) } normalize_data(kwargs) response = self.client.respond_activity_task_failed(**kwargs) return response
def respond_decision_task_completed(self, task_token, decisions=None, exec_context=None): """Wrapper for `boto3.client('swf').respond_decision_task_completed`.""" kwargs = { 'taskToken': str_or_none(task_token), 'decisions': decisions or [], 'executionContext': str_or_none(exec_context) } normalize_data(kwargs) response = self.client.respond_decision_task_completed(**kwargs) return response
def describe_workflow_type(self, domain, name, version): """Wrapper for `boto3.client('swf').describe_workflow_type`.""" kwargs = { 'domain': str_or_none(domain), 'workflowType': { 'name': str_or_none(name), 'version': str_or_none(version) } } normalize_data(kwargs) response = self.client.describe_workflow_type(**kwargs) return response
def poll_for_activity_task(self, domain, task_list, identity=None): """Wrapper for `boto3.client('swf').poll_for_activity_task`.""" identity = str(identity)[:IDENTITY_SIZE] if identity else identity kwargs = { 'domain': str_or_none(domain), 'taskList': { 'name': str_or_none(task_list), }, 'identity': identity, } normalize_data(kwargs) response = self.client.poll_for_activity_task(**kwargs) return response
def fail_workflow_execution(self, reason=None, details=None): """ Closes the workflow execution and records a WorkflowExecutionFailed event in the history. """ d = { 'decisionType': 'FailWorkflowExecution', 'failWorkflowExecutionDecisionAttributes': { 'reason': str_or_none(reason), 'details': str_or_none(details) }, } normalize_data(d) self._data.append(d)
def conf_workflow(self, dep_name, version, name=None, task_list=None, workflow_duration=None, decision_duration=None, child_policy=None, serialize_input=None, deserialize_result=None, retry=(0, 0, 0)): """Same as conf_activity but for sub-workflows.""" if name is None: name = dep_name proxy_factory = SWFWorkflowProxyFactory( identity=str(dep_name), name=str(name), version=str(version), task_list=str_or_none(task_list), workflow_duration=duration_encode(workflow_duration, 'workflow_duration'), decision_duration=duration_encode(decision_duration, 'decision_duration'), child_policy=cp_encode(child_policy), serialize_input=serialize_input, deserialize_result=deserialize_result, retry=retry) self.conf_proxy_factory(dep_name, proxy_factory)
def _cvt_values(self): """Convert values to their expected types or bailout.""" d_t_l = str_or_none(self.default_task_list) d_w_d = timer_encode(self.default_workflow_duration, 'default_workflow_duration') d_d_d = timer_encode(self.default_decision_duration, 'default_decision_duration') d_c_p = cp_encode(self.default_child_policy) return d_t_l, d_w_d, d_d_d, d_c_p
def start_timer(self, start_to_fire_timeout, timer_id, control=None): """ Starts a timer for this workflow execution and records a TimerStarted event in the history. This timer will fire after the specified delay and record a TimerFired event. :param int start_to_fire_timeout: the duration in seconds to wait before firing the timer :param timer_id: the unique ID of the timer :param control: data attached to the event that can be used by the decider in subsequent workflow tasks """ d = { 'decisionType': 'StartTimer', 'startTimerDecisionAttributes': { 'timerId': timer_id, 'control': str_or_none(control), 'startToFireTimeout': duration_encode(start_to_fire_timeout, 'start_to_fire_timeout') } } normalize_data(d) self._data.append(d)
def _cvt_values(self): """Convert values to their expected types or bailout.""" d_t_l = str_or_none(self.default_task_list) d_h = timer_encode(self.default_heartbeat, 'default_heartbeat') d_sch_c = timer_encode(self.default_schedule_to_close, 'default_schedule_to_close') d_sch_s = timer_encode(self.default_schedule_to_start, 'default_schedule_to_start') d_s_c = timer_encode(self.default_start_to_close, 'default_start_to_close') return d_t_l, d_h, d_sch_c, d_sch_s, d_s_c
def register_workflow_type(self, domain, name, version, desc=None, default_task_list=None, default_priority=None, default_task_timeout=None, default_exec_timeout=None, default_child_policy=None, default_lambda_role=None): """Wrapper for `boto3.client('swf').register_workflow_type`.""" kwargs = { 'domain': str_or_none(domain), 'name': str_or_none(name), 'version': str_or_none(version), 'description': str_or_none(desc), 'defaultTaskList': { 'name': str_or_none(default_task_list) }, 'defaultTaskPriority': str_or_none(default_priority), 'defaultTaskStartToCloseTimeout': duration_encode(default_task_timeout, 'default_task_timeout'), 'defaultExecutionStartToCloseTimeout': duration_encode(default_exec_timeout, 'default_exec_timeout'), 'defaultChildPolicy': cp_encode(default_child_policy), 'defaultLambdaRole': str_or_none(default_lambda_role) } normalize_data(kwargs) response = self.client.register_workflow_type(**kwargs) return response
def _cvt_values(self): """Convert values to their expected types or bailout.""" d_t_l = str_or_none(self.default_task_list) d_w_d = duration_encode(self.default_workflow_duration, 'default_workflow_duration') d_d_d = duration_encode(self.default_decision_duration, 'default_decision_duration') d_c_p = cp_encode(self.default_child_policy) return d_t_l, d_w_d, d_d_d, d_c_p
def continue_as_new_workflow_execution( self, child_policy=None, execution_start_to_close_timeout=None, input=None, tag_list=None, task_list=None, task_priority=None, start_to_close_timeout=None, workflow_type_version=None, lambda_role=None): """ Closes the workflow execution and starts a new workflow execution of the same type using the same workflow id and a unique run Id. A WorkflowExecutionContinuedAsNew event is recorded in the history. """ d = { 'decisionType': 'ContinueAsNewWorkflowExecution', 'continueAsNewWorkflowExecutionDecisionAttributes': { 'input': str_or_none(input), 'executionStartToCloseTimeout': duration_encode(execution_start_to_close_timeout, 'execution_start_to_close_timeout'), 'taskList': { 'name': str_or_none(task_list) }, 'taskPriority': str_or_none(task_priority), 'taskStartToCloseTimeout': duration_encode(start_to_close_timeout, 'start_to_close_timeout'), 'childPolicy': cp_encode(child_policy), 'tagList': tags_encode(tag_list), 'workflowTypeVersion': str_or_none(workflow_type_version), 'lambdaRole': str_or_none(lambda_role) } } normalize_data(d) self._data.append(d)
def poll_for_decision_task(self, domain, task_list, identity=None, next_page_token=None, max_page_size=1000, reverse_order=False): """Wrapper for `boto3.client('swf').poll_for_decision_task`.""" assert max_page_size <= 1000, 'Page size greater than 1000.' identity = str(identity)[:IDENTITY_SIZE] if identity else identity kwargs = { 'domain': str_or_none(domain), 'taskList': { 'name': str_or_none(task_list) }, 'identity': identity, 'nextPageToken': str_or_none(next_page_token), 'maximumPageSize': max_page_size, 'reverseOrder': reverse_order } normalize_data(kwargs) response = self.client.poll_for_decision_task(**kwargs) return response
def _cvt_values(self): """Convert values to their expected types or bailout.""" d_t_l = str_or_none(self.default_task_list) d_h = duration_encode(self.default_heartbeat, 'default_heartbeat') d_sch_c = duration_encode(self.default_schedule_to_close, 'default_schedule_to_close') d_sch_s = duration_encode(self.default_schedule_to_start, 'default_schedule_to_start') d_s_c = duration_encode(self.default_start_to_close, 'default_start_to_close') return d_t_l, d_h, d_sch_c, d_sch_s, d_s_c
def register_activity_type(self, domain, name, version, desc=None, default_task_list=None, default_priority=None, default_heartbeat_timeout=None, default_exec_timeout=None, default_start_timeout=None, default_close_timeout=None): """Wrapper for `boto3.client('swf').register_activity_type`.""" kwargs = { 'domain': str_or_none(domain), 'name': str_or_none(name), 'version': str_or_none(version), 'description': str_or_none(desc), 'defaultTaskList': { 'name': str_or_none(default_task_list) }, 'defaultTaskPriority': str_or_none(default_priority), 'defaultTaskHeartbeatTimeout': duration_encode(default_heartbeat_timeout, 'default_heartbeat_timeout'), 'defaultTaskStartToCloseTimeout': duration_encode(default_exec_timeout, 'default_exec_timeout'), 'defaultTaskScheduleToStartTimeout': duration_encode(default_start_timeout, 'default_start_timeout'), 'defaultTaskScheduleToCloseTimeout': duration_encode(default_close_timeout, 'default_close_timeout') } normalize_data(kwargs) response = self.client.register_activity_type(**kwargs) return response
def complete_workflow_execution(self, result=None): """ Closes the workflow execution and records a WorkflowExecutionCompleted event in the history """ d = { 'decisionType': 'CompleteWorkflowExecution', 'completeWorkflowExecutionDecisionAttributes': { 'result': str_or_none(result) } } normalize_data(d) self._data.append(d)
def cancel_workflow_execution(self, details=None): """ Closes the workflow execution and records a WorkflowExecutionCanceled event in the history. """ d = { 'decisionType': 'CancelWorkflowExecution', 'cancelWorkflowExecutionDecisionAttributes': { 'details': str_or_none(details) } } normalize_data(d) self._data.append(d)
def poll_first_page(layer1, domain, task_list, identity=None): """Return the response from loading the first page. In case of errors, empty responses or whatnot retry until a valid response. """ swf_response = {} while 'taskToken' not in swf_response or not swf_response['taskToken']: try: swf_response = layer1.poll_for_decision_task( str(domain), str(task_list), str_or_none(identity)) except SWFResponseError: logger.exception('Error while polling for decisions:') return swf_response
def poll_response_page(layer1, domain, task_list, token, identity=None): """Return a specific page. In case of errors retry a number of times.""" swf_response = None for _ in range(7): # give up after a limited number of retries try: swf_response = layer1.poll_for_decision_task( str(domain), str(task_list), str_or_none(identity), next_page_token=str(token)) break except SWFResponseError: logger.exception('Error while polling for decision page:') else: raise _PaginationError() return swf_response
def conf_activity(self, dep_name, version, name=None, task_list=None, heartbeat=None, schedule_to_close=None, schedule_to_start=None, start_to_close=None, serialize_input=None, deserialize_result=None, retry=(0, 0, 0)): """Configure an activity dependency for a workflow implementation. dep_name is the name of one of the workflow factory arguments (dependency). For example: class MyWorkflow: def __init__(self, a, b): # Two dependencies: a and b self.a = a self.b = b def run(self, n): pass cfg = SWFWorkflowConfig(version=1) cfg.conf_activity('a', name='MyActivity', version=1) cfg.conf_activity('b', version=2, task_list='my_tl') For convenience, if the activity name is missing, it will be the same as the dependency name. """ if name is None: name = dep_name proxy_factory = SWFActivityProxyFactory( identity=str(dep_name), name=str(name), version=str(version), task_list=str_or_none(task_list), heartbeat=duration_encode(heartbeat, 'heartbeat'), schedule_to_close=duration_encode(schedule_to_close, 'schedule_to_close'), schedule_to_start=duration_encode(schedule_to_start, 'schedule_to_start'), start_to_close=duration_encode(start_to_close, 'start_to_close'), serialize_input=serialize_input, deserialize_result=deserialize_result, retry=retry) self.conf_proxy_factory(dep_name, proxy_factory)
def record_marker(self, marker_name, details=None): """ Records a MarkerRecorded event in the history. Markers can be used for adding custom information in the history for instance to let deciders know that they do not need to look at the history beyond the marker event. :param str marker_name: the name if the marker """ d = { 'decisionType': 'RecordMarker', 'recordMarkerDecisionAttributes': { 'markerName': marker_name, 'details': str_or_none(details) } } normalize_data(d) self._data.append(d)
def conf_activity(self, dep_name, version, name=None, task_list=None, heartbeat=None, schedule_to_close=None, schedule_to_start=None, start_to_close=None, serialize_input=None, deserialize_result=None, retry=(0, 0, 0)): """Configure an activity dependency for a workflow implementation. dep_name is the name of one of the workflow factory arguments (dependency). For example: class MyWorkflow: def __init__(self, a, b): # Two dependencies: a and b self.a = a self.b = b def run(self, n): pass cfg = SWFWorkflowConfig(version=1) cfg.conf_activity('a', name='MyActivity', version=1) cfg.conf_activity('b', version=2, task_list='my_tl') For convenience, if the activity name is missing, it will be the same as the dependency name. """ if name is None: name = dep_name proxy_factory = SWFActivityProxyFactory( identity=str(dep_name), name=str(name), version=str(version), task_list=str_or_none(task_list), heartbeat=timer_encode(heartbeat, 'heartbeat'), schedule_to_close=timer_encode(schedule_to_close, 'schedule_to_close'), schedule_to_start=timer_encode(schedule_to_start, 'schedule_to_start'), start_to_close=timer_encode(start_to_close, 'start_to_close'), serialize_input=serialize_input, deserialize_result=deserialize_result, retry=retry) self.conf_proxy_factory(dep_name, proxy_factory)
def conf_workflow(self, dep_name, version, name=None, task_list=None, workflow_duration=None, decision_duration=None, child_policy=None, serialize_input=None, deserialize_result=None, retry=(0, 0, 0)): """Same as conf_activity but for sub-workflows.""" if name is None: name = dep_name proxy_factory = SWFWorkflowProxyFactory( identity=str(dep_name), name=str(name), version=str(version), task_list=str_or_none(task_list), workflow_duration=timer_encode(workflow_duration, 'workflow_duration'), decision_duration=timer_encode(decision_duration, 'decision_duration'), child_policy=cp_encode(child_policy), serialize_input=serialize_input, deserialize_result=deserialize_result, retry=retry) self.conf_proxy_factory(dep_name, proxy_factory)
def schedule_activity_task(self, activity_id, activity_type_name, activity_type_version, task_list=None, task_priority=None, control=None, heartbeat_timeout=None, schedule_to_close_timeout=None, schedule_to_start_timeout=None, start_to_close_timeout=None, input=None): """ Schedules an activity task. :type activity_id: string :param activity_id: The activityId of the type of the activity being scheduled. :type activity_type_name: string :param activity_type_name: The name of the type of the activity being scheduled. :type activity_type_version: string|int|float :param activity_type_version: The version of the type of the activity being scheduled. :type task_list: string :param task_list: If set, specifies the name of the task list in which to schedule the activity task. If not specified, the defaultTaskList registered with the activity type will be used. Note: a task list for this activity task must be specified either as a default for the activity type or through this field. If neither this field is set nor a default task list was specified at registration time then a fault will be returned. """ d = { 'decisionType': 'ScheduleActivityTask', 'scheduleActivityTaskDecisionAttributes': { 'activityId': activity_id, 'activityType': { 'name': activity_type_name, 'version': str(activity_type_version) }, 'taskList': { 'name': str_or_none(task_list) }, 'taskPriority': str_or_none(task_priority), 'control': control, 'heartbeatTimeout': duration_encode(heartbeat_timeout, 'heartbeat_timeout'), 'scheduleToCloseTimeout': duration_encode(schedule_to_close_timeout, 'schedule_to_close_timeout'), 'scheduleToStartTimeout': duration_encode(schedule_to_start_timeout, 'schedule_to_start_timeout'), 'startToCloseTimeout': duration_encode(start_to_close_timeout, 'start_to_close_timeout'), 'input': str_or_none(input) } } normalize_data(d) self._data.append(d)