From c10019cd25b363d8a1d278f5adc72ac69beea7da Mon Sep 17 00:00:00 2001 From: Quanzheng Long Date: Mon, 22 May 2023 11:43:53 -0700 Subject: [PATCH] Add iwf.WorkflowStateDefaultsNoWaitUntil (#62) --- integ/no_startstate_workflow.go | 3 +-- integ/skip_wait_until_state1.go | 3 +-- integ/skip_wait_until_state2.go | 3 +-- integ/workflow_uncompleted_test.go | 10 +++++----- iwf/errors.go | 2 +- iwf/workflow_state.go | 19 ++++++++++++++++--- 6 files changed, 25 insertions(+), 15 deletions(-) diff --git a/integ/no_startstate_workflow.go b/integ/no_startstate_workflow.go index 8659b71..42356e3 100644 --- a/integ/no_startstate_workflow.go +++ b/integ/no_startstate_workflow.go @@ -29,8 +29,7 @@ func (b noStartStateWorkflow) TestRPC(ctx iwf.WorkflowContext, input iwf.Object, } type noStartStateWorkflowState1 struct { - iwf.WorkflowStateDefaults - iwf.NoWaitUntil + iwf.WorkflowStateDefaultsNoWaitUntil } func (b noStartStateWorkflowState1) Execute(ctx iwf.WorkflowContext, input iwf.Object, commandResults iwf.CommandResults, persistence iwf.Persistence, communication iwf.Communication) (*iwf.StateDecision, error) { diff --git a/integ/skip_wait_until_state1.go b/integ/skip_wait_until_state1.go index 523421a..63911b5 100644 --- a/integ/skip_wait_until_state1.go +++ b/integ/skip_wait_until_state1.go @@ -5,8 +5,7 @@ import ( ) type skipWaitUntilState1 struct { - iwf.WorkflowStateDefaults - iwf.NoWaitUntil + iwf.WorkflowStateDefaultsNoWaitUntil } func (b skipWaitUntilState1) Execute(ctx iwf.WorkflowContext, input iwf.Object, commandResults iwf.CommandResults, persistence iwf.Persistence, communication iwf.Communication) (*iwf.StateDecision, error) { diff --git a/integ/skip_wait_until_state2.go b/integ/skip_wait_until_state2.go index 14a2b59..d51bcb0 100644 --- a/integ/skip_wait_until_state2.go +++ b/integ/skip_wait_until_state2.go @@ -5,8 +5,7 @@ import ( ) type skipWaitUntilState2 struct { - iwf.WorkflowStateDefaults - iwf.NoWaitUntil + iwf.WorkflowStateDefaultsNoWaitUntil } func (b skipWaitUntilState2) Execute(ctx iwf.WorkflowContext, input iwf.Object, commandResults iwf.CommandResults, persistence iwf.Persistence, communication iwf.Communication) (*iwf.StateDecision, error) { diff --git a/integ/workflow_uncompleted_test.go b/integ/workflow_uncompleted_test.go index f3b9c23..87c574b 100644 --- a/integ/workflow_uncompleted_test.go +++ b/integ/workflow_uncompleted_test.go @@ -29,7 +29,7 @@ func TestWorkflowTimeout(t *testing.T) { assert.Nil(t, out) assert.Equal(t, err, err2) - assert.Equal(t, "workflow is not completed succesfully, closedStatus: TIMEOUT, failedErrorType(applies if failed as closedStatus):, error message:", err.Error()) + assert.Equal(t, "workflow is not completed successfully, closedStatus: TIMEOUT, failedErrorType(applies if failed as closedStatus):, error message:", err.Error()) } func TestWorkflowCancel(t *testing.T) { @@ -51,7 +51,7 @@ func TestWorkflowCancel(t *testing.T) { assert.Nil(t, out) assert.Equal(t, err, err2) - assert.Equal(t, "workflow is not completed succesfully, closedStatus: CANCELED, failedErrorType(applies if failed as closedStatus):, error message:", err.Error()) + assert.Equal(t, "workflow is not completed successfully, closedStatus: CANCELED, failedErrorType(applies if failed as closedStatus):, error message:", err.Error()) } func TestForceFailWorkflow(t *testing.T) { @@ -69,7 +69,7 @@ func TestForceFailWorkflow(t *testing.T) { out, err2 := client.GetComplexWorkflowResults(context.Background(), wfId, "") assert.Nil(t, out) assert.Equal(t, err, err2) - assert.Equal(t, "workflow is not completed succesfully, closedStatus: FAILED, failedErrorType(applies if failed as closedStatus):STATE_DECISION_FAILING_WORKFLOW_ERROR_TYPE, error message:", err.Error()) + assert.Equal(t, "workflow is not completed successfully, closedStatus: FAILED, failedErrorType(applies if failed as closedStatus):STATE_DECISION_FAILING_WORKFLOW_ERROR_TYPE, error message:", err.Error()) var output string err = wErr.GetStateResult(0, &output) @@ -95,7 +95,7 @@ func TestStateApiFailWorkflow(t *testing.T) { assert.Nil(t, out) assert.Equal(t, err, err2) - assert.True(t, strings.Contains(err.Error(), "workflow is not completed succesfully, closedStatus: FAILED, failedErrorType(applies if failed as closedStatus):STATE_API_FAIL_MAX_OUT_RETRY_ERROR_TYPE, error message:statusCode: 400, responseBody: {\"error\":\"error message:test api failing")) + assert.True(t, strings.Contains(err.Error(), "workflow is not completed successfully, closedStatus: FAILED, failedErrorType(applies if failed as closedStatus):STATE_API_FAIL_MAX_OUT_RETRY_ERROR_TYPE, error message:statusCode: 400, responseBody: {\"error\":\"error message:test api failing")) } func TestStateApiTimeoutWorkflow(t *testing.T) { @@ -112,7 +112,7 @@ func TestStateApiTimeoutWorkflow(t *testing.T) { fmt.Println(err) - expectedMsg := "workflow is not completed succesfully, closedStatus: FAILED, failedErrorType(applies if failed as closedStatus):STATE_API_FAIL_MAX_OUT_RETRY_ERROR_TYPE, error message:activity error (type: StateApiWaitUntil, scheduledEventID: 9, startedEventID: 10, identity: ): activity StartToClose timeout (type: StartToClose)" + expectedMsg := "workflow is not completed successfully, closedStatus: FAILED, failedErrorType(applies if failed as closedStatus):STATE_API_FAIL_MAX_OUT_RETRY_ERROR_TYPE, error message:activity error (type: StateApiWaitUntil, scheduledEventID: 9, startedEventID: 10, identity: ): activity StartToClose timeout (type: StartToClose)" assert.Equal(t, expectedMsg, err.Error()) out, err2 := client.GetComplexWorkflowResults(context.Background(), wfId, "") diff --git a/iwf/errors.go b/iwf/errors.go index c5b9eca..e201ae8 100644 --- a/iwf/errors.go +++ b/iwf/errors.go @@ -207,7 +207,7 @@ func (w *WorkflowUncompletedError) Error() string { if w.ErrorMessage != nil { message = fmt.Sprintf("%v", *w.ErrorMessage) } - return fmt.Sprintf("workflow is not completed succesfully, closedStatus: %v, failedErrorType(applies if failed as closedStatus):%v, error message:%v", + return fmt.Sprintf("workflow is not completed successfully, closedStatus: %v, failedErrorType(applies if failed as closedStatus):%v, error message:%v", w.ClosedStatus, errTypeMsg, message) } diff --git a/iwf/workflow_state.go b/iwf/workflow_state.go index 14cf732..4791b55 100644 --- a/iwf/workflow_state.go +++ b/iwf/workflow_state.go @@ -18,7 +18,8 @@ type WorkflowState interface { // 3. In case of dynamic workflow state implementation, return customized values instead of using empty string GetStateId() string - // WaitUntil is the method to set up commands set up to wait for, before `Execute` API is invoked + // WaitUntil is the method to set up commands set up to wait for, before `Execute` API is invoked. + // It's optional -- use iwf.WorkflowStateDefaultsNoWaitUntil or iwf.NoWaitUntil to skip this step( Execute will be invoked instead) // // ctx the context info of this API invocation, like workflow start time, workflowId, etc // input the state input @@ -33,7 +34,7 @@ type WorkflowState interface { /// WaitUntil(ctx WorkflowContext, input Object, persistence Persistence, communication Communication) (*CommandRequest, error) - // Execute is the method to execute and decide what to do next + // Execute is the method to execute and decide what to do next. Invoke after commands from WaitUntil are completed, or there is WaitUntil is not implemented for the state. // // ctx the context info of this API invocation, like workflow start time, workflowId, etc // input the state input @@ -74,6 +75,18 @@ type WorkflowStateDefaults struct { DefaultStateOptions } +// WorkflowStateDefaultsNoWaitUntil is a convenient struct to put into your state implementation to save the boilerplate code. Eg: +// Example usage: +// +// type myStateImpl struct{ +// WorkflowStateDefaultsNoWaitUntil +// } +type WorkflowStateDefaultsNoWaitUntil struct { + DefaultStateId + DefaultStateOptions + NoWaitUntil +} + type DefaultStateId struct{} func (d DefaultStateId) GetStateId() string { @@ -107,7 +120,7 @@ func ShouldSkipWaitUntilAPI(state WorkflowState) bool { for i := 0; i < t.NumField(); i++ { field := t.Field(i) - if field.Type.String() == "iwf.NoWaitUntil" { + if field.Type.String() == "iwf.NoWaitUntil" || field.Type.String() == "iwf.WorkflowStateDefaultsNoWaitUntil" { return true } }