Skip to content

Commit

Permalink
Add iwf.WorkflowStateDefaultsNoWaitUntil (#62)
Browse files Browse the repository at this point in the history
  • Loading branch information
longquanzheng committed May 22, 2023
1 parent be3de1a commit c10019c
Show file tree
Hide file tree
Showing 6 changed files with 25 additions and 15 deletions.
3 changes: 1 addition & 2 deletions integ/no_startstate_workflow.go
Expand Up @@ -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) {
Expand Down
3 changes: 1 addition & 2 deletions integ/skip_wait_until_state1.go
Expand Up @@ -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) {
Expand Down
3 changes: 1 addition & 2 deletions integ/skip_wait_until_state2.go
Expand Up @@ -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) {
Expand Down
10 changes: 5 additions & 5 deletions integ/workflow_uncompleted_test.go
Expand Up @@ -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):<nil>, error message:<nil>", err.Error())
assert.Equal(t, "workflow is not completed successfully, closedStatus: TIMEOUT, failedErrorType(applies if failed as closedStatus):<nil>, error message:<nil>", err.Error())
}

func TestWorkflowCancel(t *testing.T) {
Expand All @@ -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):<nil>, error message:<nil>", err.Error())
assert.Equal(t, "workflow is not completed successfully, closedStatus: CANCELED, failedErrorType(applies if failed as closedStatus):<nil>, error message:<nil>", err.Error())
}

func TestForceFailWorkflow(t *testing.T) {
Expand All @@ -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:<nil>", 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:<nil>", err.Error())

var output string
err = wErr.GetStateResult(0, &output)
Expand All @@ -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) {
Expand All @@ -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, "")
Expand Down
2 changes: 1 addition & 1 deletion iwf/errors.go
Expand Up @@ -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)
}

Expand Down
19 changes: 16 additions & 3 deletions iwf/workflow_state.go
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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
}
}
Expand Down

0 comments on commit c10019c

Please sign in to comment.