diff --git a/integ/workflow/any_command_close/routers.go b/integ/workflow/any_command_close/routers.go index 4887850d..3b00cbd5 100644 --- a/integ/workflow/any_command_close/routers.go +++ b/integ/workflow/any_command_close/routers.go @@ -10,6 +10,16 @@ import ( "net/http" ) +/** + * This test workflow has 2 states, using REST controller to implement the workflow directly. + * + * State1: + * - WaitUntil wait until a signal is received + * - Execute method will fire the signal and move the State2 + * State2: + * - Waits on nothing. Will execute momentarily + * - Execute method will gracefully complete workflow + */ const ( WorkflowType = "any_command_close" State1 = "S1" @@ -41,7 +51,9 @@ func (h *handler) ApiV1WorkflowStateStart(c *gin.Context) { if req.GetWorkflowType() == WorkflowType { h.invokeHistory[req.GetWorkflowStateId()+"_start"]++ + if req.GetWorkflowStateId() == State1 { + // Proceed after either signal is received c.JSON(http.StatusOK, iwfidl.WorkflowStateStartResponse{ CommandRequest: &iwfidl.CommandRequest{ SignalCommands: []iwfidl.SignalCommand{ @@ -60,6 +72,7 @@ func (h *handler) ApiV1WorkflowStateStart(c *gin.Context) { return } if req.GetWorkflowStateId() == State2 { + // Go straight to the decide methods without any commands c.JSON(http.StatusOK, iwfidl.WorkflowStateStartResponse{ CommandRequest: &iwfidl.CommandRequest{ DeciderTriggerType: iwfidl.ALL_COMMAND_COMPLETED.Ptr(), @@ -82,10 +95,12 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { if req.GetWorkflowType() == WorkflowType { h.invokeHistory[req.GetWorkflowStateId()+"_decide"]++ + if req.GetWorkflowStateId() == State1 { signalResults := req.GetCommandResults() h.invokeData["signalCommandResultsLength"] = len(signalResults.SignalResults) + // Trigger signals h.invokeData["signalChannelName0"] = signalResults.SignalResults[0].GetSignalChannelName() h.invokeData["signalCommandId0"] = signalResults.SignalResults[0].GetCommandId() h.invokeData["signalStatus0"] = signalResults.SignalResults[0].GetSignalRequestStatus() @@ -95,6 +110,7 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { h.invokeData["signalStatus1"] = signalResults.SignalResults[1].GetSignalRequestStatus() h.invokeData["signalValue1"] = signalResults.SignalResults[1].GetSignalValue() + // Move to State 2 c.JSON(http.StatusOK, iwfidl.WorkflowStateDecideResponse{ StateDecision: &iwfidl.StateDecision{ NextStates: []iwfidl.StateMovement{ @@ -106,7 +122,7 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { }) return } else if req.GetWorkflowStateId() == State2 { - // go to complete + // Move to completion c.JSON(http.StatusOK, iwfidl.WorkflowStateDecideResponse{ StateDecision: &iwfidl.StateDecision{ NextStates: []iwfidl.StateMovement{ diff --git a/integ/workflow/any_command_combination/routers.go b/integ/workflow/any_command_combination/routers.go index bf0af376..fc497198 100644 --- a/integ/workflow/any_command_combination/routers.go +++ b/integ/workflow/any_command_combination/routers.go @@ -11,6 +11,16 @@ import ( "time" ) +/** + * This test workflow has 2 states, using REST controller to implement the workflow directly. + * + * State1: + * - WaitUntil will fail its first attempt and then retry which will proceed when a combination is completed + * - Execute method will invoke the combination and move the State2 + * State2: + * - WaitUntil will fail its first attempt and then retry which will proceed when a combination is completed + * - Execute method will invoke the combination and gracefully complete workflow + */ const ( WorkflowType = "any_command_combination" State1 = "S1" @@ -88,7 +98,9 @@ func (h *handler) ApiV1WorkflowStateStart(c *gin.Context) { if req.GetWorkflowType() == WorkflowType { h.invokeHistory[req.GetWorkflowStateId()+"_start"]++ + if req.GetWorkflowStateId() == State1 { + // If the state has already retried an invalid command, proceed on combination completed if h.hasS1RetriedForInvalidCommandId { startResp := iwfidl.WorkflowStateStartResponse{ CommandRequest: &iwfidl.CommandRequest{ @@ -112,6 +124,8 @@ func (h *handler) ApiV1WorkflowStateStart(c *gin.Context) { c.JSON(http.StatusOK, startResp) } else { + // If the state has not already retried an invalid command, return invalid trigger signals, which will fail + // and cause a retry startResp := iwfidl.WorkflowStateStartResponse{ CommandRequest: &iwfidl.CommandRequest{ SignalCommands: validSignalCommands, @@ -124,7 +138,9 @@ func (h *handler) ApiV1WorkflowStateStart(c *gin.Context) { } return } + if req.GetWorkflowStateId() == State2 { + // If the state has already retried an invalid command, return signals and completion metrics if h.hasS2RetriedForInvalidCommandId { startResp := iwfidl.WorkflowStateStartResponse{ CommandRequest: &iwfidl.CommandRequest{ @@ -148,6 +164,8 @@ func (h *handler) ApiV1WorkflowStateStart(c *gin.Context) { c.JSON(http.StatusOK, startResp) } else { + // If the state has not already retried an invalid command, return invalid trigger signals, which will fail + // and cause a retry startResp := iwfidl.WorkflowStateStartResponse{ CommandRequest: &iwfidl.CommandRequest{ SignalCommands: invalidSignalCommands, @@ -174,6 +192,8 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { if req.GetWorkflowType() == WorkflowType { h.invokeHistory[req.GetWorkflowStateId()+"_decide"]++ + + // Trigger signals and move to State 2 if req.GetWorkflowStateId() == State1 { h.invokeData["s1_commandResults"] = req.GetCommandResults() @@ -188,9 +208,8 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { }) return } else if req.GetWorkflowStateId() == State2 { + // Trigger data and move to completion h.invokeData["s2_commandResults"] = req.GetCommandResults() - - // go to complete c.JSON(http.StatusOK, iwfidl.WorkflowStateDecideResponse{ StateDecision: &iwfidl.StateDecision{ NextStates: []iwfidl.StateMovement{ diff --git a/integ/workflow/any_timer_signal/routers.go b/integ/workflow/any_timer_signal/routers.go index e0be00aa..00249b4b 100644 --- a/integ/workflow/any_timer_signal/routers.go +++ b/integ/workflow/any_timer_signal/routers.go @@ -11,6 +11,16 @@ import ( "time" ) +/** + * This test workflow has 2 states, using REST controller to implement the workflow directly. + * + * State1: + * - WaitUntil will wait for the signals to trigger. + * - Execute method will trigger signals and retry State1 once, then trigger signals and move the State2 + * State2: + * - Waits on nothing. Will execute momentarily + * - Execute method will gracefully complete workflow + */ const ( WorkflowType = "any_timer_signal" State1 = "S1" @@ -41,9 +51,12 @@ func (h *handler) ApiV1WorkflowStateStart(c *gin.Context) { if req.GetWorkflowType() == WorkflowType { h.invokeHistory[req.GetWorkflowStateId()+"_start"]++ + if req.GetWorkflowStateId() == State1 { var timerCommands []iwfidl.TimerCommand context := req.GetContext() + + // Fire timer after 1s on first start attempt if context.GetStateExecutionId() == State1+"-"+"1" { now := time.Now().Unix() timerCommands = []iwfidl.TimerCommand{ @@ -67,7 +80,9 @@ func (h *handler) ApiV1WorkflowStateStart(c *gin.Context) { }) return } + if req.GetWorkflowStateId() == State2 { + // Go straight to the decide methods without any commands c.JSON(http.StatusOK, iwfidl.WorkflowStateStartResponse{ CommandRequest: &iwfidl.CommandRequest{ DeciderTriggerType: iwfidl.ALL_COMMAND_COMPLETED.Ptr(), @@ -95,12 +110,14 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { var movements []iwfidl.StateMovement context := req.GetContext() + // On first State 1 attempt, trigger signals and stay on the first state if context.GetStateExecutionId() == State1+"-"+"1" { h.invokeData["signalChannelName1"] = signalResults.SignalResults[0].GetSignalChannelName() h.invokeData["signalCommandId1"] = signalResults.SignalResults[0].GetCommandId() h.invokeData["signalStatus1"] = signalResults.SignalResults[0].GetSignalRequestStatus() movements = []iwfidl.StateMovement{{StateId: State1}} } else { + // After the first State 1 attempt, trigger signals and move to next state h.invokeData["signalChannelName2"] = signalResults.SignalResults[0].GetSignalChannelName() h.invokeData["signalCommandId2"] = signalResults.SignalResults[0].GetCommandId() h.invokeData["signalStatus2"] = signalResults.SignalResults[0].GetSignalRequestStatus() @@ -115,7 +132,7 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { }) return } else if req.GetWorkflowStateId() == State2 { - // go to complete + // Move to completion c.JSON(http.StatusOK, iwfidl.WorkflowStateDecideResponse{ StateDecision: &iwfidl.StateDecision{ NextStates: []iwfidl.StateMovement{ diff --git a/integ/workflow/basic/routers.go b/integ/workflow/basic/routers.go index 1309ac90..6102ae2b 100644 --- a/integ/workflow/basic/routers.go +++ b/integ/workflow/basic/routers.go @@ -8,6 +8,16 @@ import ( "net/http" ) +/** + * This test workflow has 2 states, using REST controller to implement the workflow directly. + * + * State1: + * - Waits on nothing. Will execute momentarily + * - Execute method will move to State2 + * State2: + * - Waits on nothing. Will execute momentarily + * - Execute method will gracefully complete workflow + */ const ( WorkflowType = "basic" State1 = "S1" @@ -39,7 +49,7 @@ func (h *handler) ApiV1WorkflowStateStart(c *gin.Context) { } if req.GetWorkflowType() == WorkflowType { - // basic workflow go straight to decide methods without any commands + // Basic workflow go straight to decide methods without any commands if req.GetWorkflowStateId() == State1 || req.GetWorkflowStateId() == State2 { h.invokeHistory[req.GetWorkflowStateId()+"_start"]++ c.JSON(http.StatusOK, iwfidl.WorkflowStateStartResponse{ @@ -68,8 +78,9 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { if req.GetWorkflowType() == WorkflowType { h.invokeHistory[req.GetWorkflowStateId()+"_decide"]++ + if req.GetWorkflowStateId() == State1 { - // go to S2 + // Move to next state c.JSON(http.StatusOK, iwfidl.WorkflowStateDecideResponse{ StateDecision: &iwfidl.StateDecision{ NextStates: []iwfidl.StateMovement{ @@ -98,7 +109,7 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { }) return } else if req.GetWorkflowStateId() == State2 { - // go to complete + // Move to completion c.JSON(http.StatusOK, iwfidl.WorkflowStateDecideResponse{ StateDecision: &iwfidl.StateDecision{ NextStates: []iwfidl.StateMovement{ diff --git a/integ/workflow/conditional_close/routers.go b/integ/workflow/conditional_close/routers.go index a5172298..3d4f06d1 100644 --- a/integ/workflow/conditional_close/routers.go +++ b/integ/workflow/conditional_close/routers.go @@ -10,6 +10,14 @@ import ( "time" ) +/** + * This test workflow has 1 state, using REST controller to implement the workflow directly. + * + * State1: + * - WaitUntil will proceed when the channel or signal is published to + * - Execute method will continuously retry State1 until the 3rd attempt which will send a message to the channel or + * signal, making the state empty and force-complete. + */ const ( WorkflowType = "conditional_close" RpcPublishInternalChannel = "publish_internal_channel" @@ -45,6 +53,7 @@ func (h *handler) ApiV1WorkflowWorkerRpc(c *gin.Context) { log.Println("received workflow worker rpc request, ", req) h.invokeHistory[req.RpcName]++ + // Return channel name c.JSON(http.StatusOK, iwfidl.WorkflowWorkerRpcResponse{ PublishToInterStateChannel: []iwfidl.InterStateChannelPublishing{ { @@ -65,8 +74,9 @@ func (h *handler) ApiV1WorkflowStateStart(c *gin.Context) { if req.GetWorkflowType() == WorkflowType { h.invokeHistory[req.GetWorkflowStateId()+"_start"]++ - if req.GetWorkflowStateId() == State1 { + if req.GetWorkflowStateId() == State1 { + // Proceed when channel is published to cmdReq := &iwfidl.CommandRequest{ InterStateChannelCommands: []iwfidl.InterStateChannelCommand{ { @@ -76,8 +86,9 @@ func (h *handler) ApiV1WorkflowStateStart(c *gin.Context) { CommandWaitingType: ptr.Any(iwfidl.ANY_COMPLETED), } input := req.GetStateInput() + if input.GetData() == "use-signal-channel" { - // use signal + // Proceed when signal is published to cmdReq = &iwfidl.CommandRequest{ SignalCommands: []iwfidl.SignalCommand{ { @@ -87,6 +98,7 @@ func (h *handler) ApiV1WorkflowStateStart(c *gin.Context) { CommandWaitingType: ptr.Any(iwfidl.ANY_COMPLETED), } } + c.JSON(http.StatusOK, iwfidl.WorkflowStateStartResponse{ CommandRequest: cmdReq, }) @@ -112,10 +124,10 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { var internalChanPub []iwfidl.InterStateChannelPublishing context := req.GetContext() if context.GetStateExecutionId() == "S1-1" { - // wait for 3 seconds so that the channel can have a new message + // Wait for 3 seconds so that the channel can have a new message time.Sleep(time.Second * 3) } else if context.GetStateExecutionId() == "S1-3" { - // send internal channel message within the state execution + // Send internal channel message within the state execution // and expecting the messages are processed by the conditional check internalChanPub = []iwfidl.InterStateChannelPublishing{ { @@ -130,8 +142,9 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { CloseInput: &TestInput, } input := req.GetStateInput() + + // Use signal instead if input.GetData() == "use-signal-channel" { - // use signal conditionalClose = &iwfidl.WorkflowConditionalClose{ ConditionalCloseType: iwfidl.FORCE_COMPLETE_ON_SIGNAL_CHANNEL_EMPTY.Ptr(), ChannelName: iwfidl.PtrString(TestChannelName), diff --git a/integ/workflow/deadend/routers.go b/integ/workflow/deadend/routers.go index 0035c1f5..68709ecc 100644 --- a/integ/workflow/deadend/routers.go +++ b/integ/workflow/deadend/routers.go @@ -9,6 +9,17 @@ import ( "net/http" ) +/** + * This test workflow has 3 states, using REST controller to implement the workflow directly. + * + * RPCWriteData: + * - WaitUntil will upsert data attributes + * RPCTriggerState: + * - WaitUntil will move to State1 + * State1: + * - WaitUntil is skipped + * - Execute method will put the state into a dead-end. + */ const ( WorkflowType = "deadend" RPCTriggerState = "test-RPCTriggerState" @@ -46,6 +57,7 @@ func (h *handler) ApiV1WorkflowWorkerRpc(c *gin.Context) { } if req.RpcName == RPCTriggerState { + // Move to State 1 c.JSON(http.StatusOK, iwfidl.WorkflowWorkerRpcResponse{ StateDecision: &iwfidl.StateDecision{NextStates: []iwfidl.StateMovement{ { @@ -57,6 +69,7 @@ func (h *handler) ApiV1WorkflowWorkerRpc(c *gin.Context) { }}, }) } else if req.RpcName == RPCWriteData { + // Upsert data attributes c.JSON(http.StatusOK, iwfidl.WorkflowWorkerRpcResponse{ UpsertDataAttributes: []iwfidl.KeyValue{ { @@ -88,6 +101,8 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { if req.GetWorkflowType() == WorkflowType { h.invokeHistory[req.GetWorkflowStateId()+"_decide"]++ + + // Move to the dead-end state if req.GetWorkflowStateId() == State1 { c.JSON(http.StatusOK, iwfidl.WorkflowStateDecideResponse{ diff --git a/integ/workflow/headers/routers.go b/integ/workflow/headers/routers.go index 935543a0..1a2bab70 100644 --- a/integ/workflow/headers/routers.go +++ b/integ/workflow/headers/routers.go @@ -8,6 +8,13 @@ import ( "net/http" ) +/** + * This test workflow has 1 state, using REST controller to implement the workflow directly. + * + * State1: + * - WaitUntil method does nothing + * - Execute method will gracefully complete workflow + */ const ( WorkflowType = "headers" State1 = "S1" @@ -42,7 +49,7 @@ func (h *handler) ApiV1WorkflowStateStart(c *gin.Context) { log.Println("received state start request, ", req) if req.GetWorkflowType() == WorkflowType { - // basic workflow go straight to decide methods without any commands + // Basic workflow to go straight to the decide methods without any commands if req.GetWorkflowStateId() == State1 { h.invokeHistory[req.GetWorkflowStateId()+"_start"]++ c.JSON(http.StatusOK, iwfidl.WorkflowStateStartResponse{ @@ -74,7 +81,7 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { if req.GetWorkflowType() == WorkflowType { h.invokeHistory[req.GetWorkflowStateId()+"_decide"]++ if req.GetWorkflowStateId() == State1 { - // go to S1 + // Move to completion c.JSON(http.StatusOK, iwfidl.WorkflowStateDecideResponse{ StateDecision: &iwfidl.StateDecision{ NextStates: []iwfidl.StateMovement{ diff --git a/integ/workflow/interstate/routers.go b/integ/workflow/interstate/routers.go index 3986a3c5..f72b303f 100644 --- a/integ/workflow/interstate/routers.go +++ b/integ/workflow/interstate/routers.go @@ -10,6 +10,22 @@ import ( "time" ) +/** + * This test workflow has four states, using REST controller to implement the workflow directly. + * + * State1: + * - WaitUntil method does nothing + * - Execute method will move to State21 & State22: + * State21: + * - WaitUntil will proceed once channel1 has been published to + * - Execute method will move to State31: + * State22: + * - WaitUntil will delay 2s then publish on channel1 + * - Execute method will delay 2s then publish on channel2 & end in a dead-end + * State31: + * - WaitUntil will proceed once channel2 has been published to + * - Execute method will gracefully complete workflow + */ const ( WorkflowType = "interstate" State1 = "S1" @@ -55,6 +71,7 @@ func (h *handler) ApiV1WorkflowStateStart(c *gin.Context) { if req.GetWorkflowType() == WorkflowType { h.invokeHistory[req.GetWorkflowStateId()+"_start"]++ + // Go straight to the decide methods without any commands if req.GetWorkflowStateId() == State1 { c.JSON(http.StatusOK, iwfidl.WorkflowStateStartResponse{ CommandRequest: &iwfidl.CommandRequest{ @@ -63,6 +80,7 @@ func (h *handler) ApiV1WorkflowStateStart(c *gin.Context) { }) return } + // Will proceed once channel 1 has been published to if req.GetWorkflowStateId() == State21 { c.JSON(http.StatusOK, iwfidl.WorkflowStateStartResponse{ CommandRequest: &iwfidl.CommandRequest{ @@ -77,6 +95,7 @@ func (h *handler) ApiV1WorkflowStateStart(c *gin.Context) { }) return } + // Will proceed once channel 2 has been published to if req.GetWorkflowStateId() == State31 { c.JSON(http.StatusOK, iwfidl.WorkflowStateStartResponse{ CommandRequest: &iwfidl.CommandRequest{ @@ -92,6 +111,7 @@ func (h *handler) ApiV1WorkflowStateStart(c *gin.Context) { return } + // Wait 2 seconds then publish on channel1 if req.GetWorkflowStateId() == State22 { time.Sleep(time.Second * 2) c.JSON(http.StatusOK, iwfidl.WorkflowStateStartResponse{ @@ -124,6 +144,10 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { if req.GetWorkflowType() == WorkflowType { h.invokeHistory[req.GetWorkflowStateId()+"_decide"]++ if req.GetWorkflowStateId() == State1 { + // State 1 requires no pre-reqs + // Move to state 21 & 22: + // 21 - Will wait for channel 1 + // 22 - Will wait 3 seconds then publish to channel 1 c.JSON(http.StatusOK, iwfidl.WorkflowStateDecideResponse{ StateDecision: &iwfidl.StateDecision{ NextStates: []iwfidl.StateMovement{ @@ -143,6 +167,7 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { results := req.GetCommandResults() h.invokeData[State21+"received"] = results.GetInterStateChannelResults()[0].GetValue() + // Move to state 31, which will wait for channel 2 c.JSON(http.StatusOK, iwfidl.WorkflowStateDecideResponse{ StateDecision: &iwfidl.StateDecision{ NextStates: []iwfidl.StateMovement{ @@ -159,6 +184,7 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { results := req.GetCommandResults() h.invokeData[State31+"received"] = results.GetInterStateChannelResults()[0].GetValue() + // Move to completion c.JSON(http.StatusOK, iwfidl.WorkflowStateDecideResponse{ StateDecision: &iwfidl.StateDecision{ NextStates: []iwfidl.StateMovement{ @@ -174,7 +200,7 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { if req.GetWorkflowStateId() == State22 { time.Sleep(time.Second * 2) c.JSON(http.StatusOK, iwfidl.WorkflowStateDecideResponse{ - // real new dead end + // Move to the dead-end state and publish on channel 2 (to unlock State 31) StateDecision: &iwfidl.StateDecision{ NextStates: []iwfidl.StateMovement{ { diff --git a/integ/workflow/locking/routers.go b/integ/workflow/locking/routers.go index 16703643..5ccb6c17 100644 --- a/integ/workflow/locking/routers.go +++ b/integ/workflow/locking/routers.go @@ -13,6 +13,19 @@ import ( "time" ) +/** + * This test workflow has three states, using REST controller to implement the workflow directly. + * + * State1: + * - WaitUntil method does nothing + * - Execute method will move to State Waiting, and 10 instances of State 2 + * State2: + * - WaitUntil update SA + * - Execute method will update data objects and will gracefully complete workflow + * StateWaiting: + * - WaitUntil will proceed once the internal channel has been published to + * - Execute method will gracefully complete workflow + */ const ( WorkflowType = "locking" State1 = "S1" @@ -102,6 +115,8 @@ func (h *handler) ApiV1WorkflowWorkerRpc(c *gin.Context) { if input.GetEncoding() != TestValue.GetEncoding() { panic("input is incorrect") } + + // Publish to internal channel if input.GetData() == ShouldUnblockStateWaiting { c.JSON(http.StatusOK, iwfidl.WorkflowWorkerRpcResponse{ PublishToInterStateChannel: []iwfidl.InterStateChannelPublishing{ @@ -127,9 +142,9 @@ func (h *handler) ApiV1WorkflowWorkerRpc(c *gin.Context) { } h.rpcInvokes++ - // this RPC will increase both SA and DA time.Sleep(time.Millisecond) + // This RPC will increase both SA and DA saInt := int64(0) for _, sa := range req.GetSearchAttributes() { if sa.GetKey() == TestSearchAttributeIntKey { @@ -221,6 +236,7 @@ func (h *handler) ApiV1WorkflowStateStart(c *gin.Context) { if req.GetWorkflowType() == WorkflowType { h.invokeHistory[req.GetWorkflowStateId()+"_start"]++ + // Go straight to the decide methods without any commands if req.GetWorkflowStateId() == State1 { c.JSON(http.StatusOK, iwfidl.WorkflowStateStartResponse{ CommandRequest: &iwfidl.CommandRequest{ @@ -229,6 +245,7 @@ func (h *handler) ApiV1WorkflowStateStart(c *gin.Context) { }) return } + // Will proceed once the internal channel has been published to if req.GetWorkflowStateId() == StateWaiting { c.JSON(http.StatusOK, iwfidl.WorkflowStateStartResponse{ CommandRequest: &iwfidl.CommandRequest{ @@ -244,7 +261,7 @@ func (h *handler) ApiV1WorkflowStateStart(c *gin.Context) { } if req.GetWorkflowStateId() == State2 { - // this state API is to increase SA + // This state API is to increase SA time.Sleep(time.Second) saInt := int64(0) for _, sa := range req.GetSearchAttributes() { @@ -269,6 +286,7 @@ func (h *handler) ApiV1WorkflowStateStart(c *gin.Context) { }, } + // Go straight to the decide methods after updating SA c.JSON(http.StatusOK, iwfidl.WorkflowStateStartResponse{ CommandRequest: &iwfidl.CommandRequest{ DeciderTriggerType: iwfidl.ALL_COMMAND_COMPLETED.Ptr(), @@ -303,6 +321,8 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { stms = append(stms, state2Movement) } + // Move to State Waiting, and 10 instances of State 2 + // State Waiting will not complete until the internal channel has been published to c.JSON(http.StatusOK, iwfidl.WorkflowStateDecideResponse{ StateDecision: &iwfidl.StateDecision{ NextStates: stms, @@ -310,6 +330,7 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { }) return } + // Move to completion if req.GetWorkflowStateId() == StateWaiting { c.JSON(http.StatusOK, iwfidl.WorkflowStateDecideResponse{ StateDecision: &iwfidl.StateDecision{ @@ -323,7 +344,7 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { return } if req.GetWorkflowStateId() == State2 { - // this API is to increase DA + // This API is to increase DA time.Sleep(time.Second) daInt := 0 for _, da := range req.DataObjects { @@ -341,6 +362,7 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { } daInt++ context := req.GetContext() + c.JSON(http.StatusOK, iwfidl.WorkflowStateDecideResponse{ UpsertDataObjects: []iwfidl.KeyValue{ { @@ -359,6 +381,7 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { }, }, + // Move to completion StateDecision: &iwfidl.StateDecision{ NextStates: []iwfidl.StateMovement{ { diff --git a/integ/workflow/parallel/routers.go b/integ/workflow/parallel/routers.go index 4261f831..520310cf 100644 --- a/integ/workflow/parallel/routers.go +++ b/integ/workflow/parallel/routers.go @@ -10,6 +10,34 @@ import ( "time" ) +/** + * This test workflow has eight states, using REST controller to implement the workflow directly. + * + * State1: + * - WaitUntil method does nothing + * - Execute method delays 1s then moves to State11, State12, & State13 + * State11: + * - WaitUntil method does nothing + * - Execute method delays 2s then moves to State111 & State112 + * State12: + * - WaitUntil method does nothing + * - Execute method delays 2s then moves to State121 & State122 + * State13: + * - WaitUntil method does nothing + * - Execute method will delay 1s then gracefully complete workflow + * State111: + * - WaitUntil method does nothing + * - Execute method will gracefully complete workflow + * State112: + * - WaitUntil method does nothing + * - Execute method will gracefully complete workflow + * State121: + * - WaitUntil method does nothing + * - Execute method will gracefully complete workflow + * State122: + * - WaitUntil method does nothing + * - Execute method will gracefully complete workflow + */ const ( WorkflowType = "parallel" State1 = "S1" @@ -43,6 +71,8 @@ func (h *handler) ApiV1WorkflowStateStart(c *gin.Context) { if req.GetWorkflowType() == WorkflowType { h.invokeHistory[req.GetWorkflowStateId()+"_start"]++ + + // Go straight to the decide methods without any commands c.JSON(http.StatusOK, iwfidl.WorkflowStateStartResponse{ CommandRequest: &iwfidl.CommandRequest{ DeciderTriggerType: iwfidl.ALL_COMMAND_COMPLETED.Ptr(), @@ -67,9 +97,10 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { var nextStates []iwfidl.StateMovement switch req.GetWorkflowStateId() { case State1: - // cause graceful complete to wait + // Cause graceful complete to wait time.Sleep(time.Second * 1) + // Move to 3 states (which will all move to this decide method without commands) nextStates = []iwfidl.StateMovement{ { StateId: State11, @@ -82,9 +113,10 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { }, } case State11: - // cause graceful complete to wait + // Cause graceful complete to wait time.Sleep(time.Second * 2) + // Move to 2 states (which will all move to this decide method without commands) nextStates = []iwfidl.StateMovement{ { StateId: State111, @@ -94,8 +126,10 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { }, } case State12: - // cause graceful complete to wait + // Cause graceful complete to wait time.Sleep(time.Second * 2) + + // Move to 2 states (which will all move to this decide method without commands) nextStates = []iwfidl.StateMovement{ { StateId: State121, @@ -105,8 +139,10 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { }, } case State13: - // cause graceful complete to wait + // Cause graceful complete to wait time.Sleep(time.Second * 1) + + // Move to completion after updating the state input nextStates = []iwfidl.StateMovement{ { StateId: service.GracefulCompletingWorkflowStateId, @@ -116,7 +152,8 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { }, }, } - case State112, State121, State122, State111: + case State111, State112, State121, State122: + // Move to completion after updating the state input nextStates = []iwfidl.StateMovement{ { StateId: service.GracefulCompletingWorkflowStateId, @@ -127,6 +164,7 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { }, } default: + // Fail workflow due to unknown or unexpected state nextStates = []iwfidl.StateMovement{ { StateId: service.ForceFailingWorkflowStateId, diff --git a/integ/workflow/persistence/routers.go b/integ/workflow/persistence/routers.go index d6134c3b..9d58e7dc 100644 --- a/integ/workflow/persistence/routers.go +++ b/integ/workflow/persistence/routers.go @@ -10,6 +10,19 @@ import ( "net/http" ) +/** + * This test workflow has three states, using REST controller to implement the workflow directly. + * + * State1: + * - WaitUntil method will update DA, SA, & SL + * - Execute method will move to State2 with partially loaded data + * State2: + * - WaitUntil method will store attribute data + * - Execute method will move to State3 with partially loaded data + * State3: + * - WaitUntil method performs some attribute checks + * - Execute method performs checks on the attribute data and then gracefully completes the workflow + */ const ( WorkflowType = "persistence" State1 = "S1" @@ -103,6 +116,7 @@ func (h *handler) ApiV1WorkflowStateStart(c *gin.Context) { }, } + // Go to the decide methods after updating DA, SA, & SL c.JSON(http.StatusOK, iwfidl.WorkflowStateStartResponse{ CommandRequest: &iwfidl.CommandRequest{ DeciderTriggerType: iwfidl.ALL_COMMAND_COMPLETED.Ptr(), @@ -129,6 +143,8 @@ func (h *handler) ApiV1WorkflowStateStart(c *gin.Context) { } if req.GetWorkflowStateId() == State2 { sas := req.GetSearchAttributes() + + // Determine how many keywords and ints are found in the search attributes kwSaFounds := 0 intSaFounds := 0 for _, sa := range sas { @@ -144,6 +160,7 @@ func (h *handler) ApiV1WorkflowStateStart(c *gin.Context) { h.invokeData["S2_start_kwSaFounds"] = kwSaFounds h.invokeData["S2_start_intSaFounds"] = intSaFounds + // Determine if the attribute is found in the request queryAttFound := false queryAtts := req.GetDataObjects() for _, queryAtt := range queryAtts { @@ -157,6 +174,7 @@ func (h *handler) ApiV1WorkflowStateStart(c *gin.Context) { } h.invokeData["S2_start_queryAttFound"] = queryAttFound + // Go straight to the decide methods without any commands c.JSON(http.StatusOK, iwfidl.WorkflowStateStartResponse{ CommandRequest: &iwfidl.CommandRequest{ DeciderTriggerType: iwfidl.ALL_COMMAND_COMPLETED.Ptr(), @@ -166,6 +184,8 @@ func (h *handler) ApiV1WorkflowStateStart(c *gin.Context) { } if req.GetWorkflowStateId() == State3 { sas := req.GetSearchAttributes() + + // Determine if the INT attribute is found in the request found := false for _, sa := range sas { if sa.GetKey() == TestSearchAttributeKeywordKey { @@ -194,6 +214,7 @@ func (h *handler) ApiV1WorkflowStateStart(c *gin.Context) { panic("missing query attribute requested by partial loading keys") } + // Go straight to the decide methods without any commands c.JSON(http.StatusOK, iwfidl.WorkflowStateStartResponse{ CommandRequest: &iwfidl.CommandRequest{ DeciderTriggerType: iwfidl.ALL_COMMAND_COMPLETED.Ptr(), @@ -218,6 +239,8 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { h.invokeHistory[req.GetWorkflowStateId()+"_decide"]++ if req.GetWorkflowStateId() == State1 { sas := req.GetSearchAttributes() + + // Determine how many keywords and ints are found in the search attributes kwSaFounds := 0 intSaFounds := 0 for _, sa := range sas { @@ -236,6 +259,7 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { queryAttFound := 0 queryAtts := req.GetDataObjects() + // Determine how many query attributes are found for _, queryAtt := range queryAtts { value := queryAtt.GetValue() if queryAtt.GetKey() == TestDataObjectKey && value.GetData() == TestDataObjectVal1.GetData() && value.GetEncoding() == TestDataObjectVal1.GetEncoding() { @@ -247,6 +271,7 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { } h.invokeData["S1_decide_queryAttFound"] = queryAttFound + // Determine if local attribute is found localAttFound := false localAtt := req.GetStateLocals()[0] value := localAtt.GetValue() @@ -269,6 +294,7 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { }, } + // Move to state 2 with set options after updating values c.JSON(http.StatusOK, iwfidl.WorkflowStateDecideResponse{ StateDecision: &iwfidl.StateDecision{ NextStates: []iwfidl.StateMovement{ @@ -303,6 +329,8 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { return } else if req.GetWorkflowStateId() == State2 { sas := req.GetSearchAttributes() + + // Determine how many keywords and ints are found in the search attributes kwSaFounds := 0 intSaFounds := 0 for _, sa := range sas { @@ -320,6 +348,8 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { queryAttFound := false queryAtts := req.GetDataObjects() + + // Determine how many query attributes are found for _, queryAtt := range queryAtts { value := queryAtt.GetValue() if queryAtt.GetKey() == TestDataObjectKey && value.GetData() == TestDataObjectVal2.GetData() && value.GetEncoding() == TestDataObjectVal2.GetEncoding() { @@ -332,6 +362,7 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { h.invokeData["S2_decide_queryAttFound"] = queryAttFound + // Move to state 3 after with set options c.JSON(http.StatusOK, iwfidl.WorkflowStateDecideResponse{ StateDecision: &iwfidl.StateDecision{ NextStates: []iwfidl.StateMovement{ @@ -359,6 +390,8 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { return } else if req.GetWorkflowStateId() == State3 { sas := req.GetSearchAttributes() + + // Determine if the INT attribute is found in the request found := false for _, sa := range sas { if sa.GetKey() == TestSearchAttributeKeywordKey { @@ -375,6 +408,8 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { queryAttFound := 0 queryAtts := req.GetDataObjects() + + // Determine how many query attributes are found for _, queryAtt := range queryAtts { if queryAtt.GetKey() == TestDataObjectKey { queryAttFound++ @@ -387,6 +422,7 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { panic("missing query attribute requested by partial loading keys") } + // Move to completion c.JSON(http.StatusOK, iwfidl.WorkflowStateDecideResponse{ StateDecision: &iwfidl.StateDecision{ NextStates: []iwfidl.StateMovement{ diff --git a/integ/workflow/persistence_loading_policy/routers.go b/integ/workflow/persistence_loading_policy/routers.go index 8aa5702c..8db274d6 100644 --- a/integ/workflow/persistence_loading_policy/routers.go +++ b/integ/workflow/persistence_loading_policy/routers.go @@ -12,6 +12,16 @@ import ( "net/http" ) +/** + * This test workflow has two states, using REST controller to implement the workflow directly. + * + * State1: + * - WaitUntil skipped + * - Execute method verifies the loaded attributes then moves to a dead-end. + * State2: + * - WaitUntil method verifies the loaded attributes + * - Execute method verifies the loaded attributes then gracefully completes the workflow + */ const ( WorkflowType = "persistence_loading_policy" State1 = "S1" @@ -45,14 +55,14 @@ func (h *handler) ApiV1WorkflowStateStart(c *gin.Context) { h.invokeHistory[req.GetWorkflowStateId()+"_start"]++ if req.GetWorkflowStateId() == State2 { - // dynamically get the loadingType from input + // Dynamically get the loadingType from input loadingTypeFromInput := req.GetStateInput() loadingType := iwfidl.PersistenceLoadingType(loadingTypeFromInput.GetData()) verifyLoadedAttributes(req.GetSearchAttributes(), req.GetDataObjects(), loadingType) } - // go straight to decide methods without any commands + // Go straight to the decide methods without any commands c.JSON(http.StatusOK, iwfidl.WorkflowStateStartResponse{ CommandRequest: &iwfidl.CommandRequest{ DeciderTriggerType: iwfidl.ANY_COMMAND_COMPLETED.Ptr(), @@ -75,7 +85,7 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { h.invokeHistory[req.GetWorkflowStateId()+"_decide"]++ - // dynamically get the loadingType from input + // Dynamically get the loadingType from input loadingTypeFromInput := req.GetStateInput() loadingType := iwfidl.PersistenceLoadingType(loadingTypeFromInput.GetData()) @@ -86,7 +96,7 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { var upsertSearchAttributes []iwfidl.SearchAttribute var upsertDataObjects []iwfidl.KeyValue - // set search attributes and data attributes in State1 + // Set search attributes and data attributes in State1 if req.GetWorkflowStateId() == State1 { upsertSearchAttributes = []iwfidl.SearchAttribute{ { @@ -119,6 +129,7 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { } } + // Move to dead-end (state 1) or completion (state 2) var nextStateId string if req.GetWorkflowStateId() == State1 { nextStateId = service.DeadEndWorkflowStateId diff --git a/integ/workflow/rpc/routers.go b/integ/workflow/rpc/routers.go index 5aa31922..b27a4012 100644 --- a/integ/workflow/rpc/routers.go +++ b/integ/workflow/rpc/routers.go @@ -10,6 +10,16 @@ import ( "net/http" ) +/** + * This test workflow has two states, using REST controller to implement the workflow directly. + * + * State1: + * - WaitUntil updates attribute data and data objects and then waits until the channel has been published to + * - Execute method moves to State2 + * State2: + * - WaitUntil method does nothing + * - Execute method will gracefully complete workflow + */ const ( WorkflowType = "rpc" State1 = "S1" @@ -124,6 +134,7 @@ func (h *handler) ApiV1WorkflowWorkerRpc(c *gin.Context) { }, } + // Proceed with State 2 after setting the attributes c.JSON(http.StatusOK, iwfidl.WorkflowWorkerRpcResponse{ Output: &TestOutput, StateDecision: &iwfidl.StateDecision{NextStates: []iwfidl.StateMovement{ @@ -183,6 +194,7 @@ func (h *handler) ApiV1WorkflowStateStart(c *gin.Context) { }, } + // Proceed after attributes and data objects have been updated and channel has been published to c.JSON(http.StatusOK, iwfidl.WorkflowStateStartResponse{ CommandRequest: &iwfidl.CommandRequest{ InterStateChannelCommands: []iwfidl.InterStateChannelCommand{ @@ -203,6 +215,7 @@ func (h *handler) ApiV1WorkflowStateStart(c *gin.Context) { return } if req.GetWorkflowStateId() == State2 { + // Go straight to the decide methods without any commands c.JSON(http.StatusOK, iwfidl.WorkflowStateStartResponse{ CommandRequest: &iwfidl.CommandRequest{ DeciderTriggerType: iwfidl.ALL_COMMAND_COMPLETED.Ptr(), @@ -233,6 +246,7 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { } h.invokeData[TestInterStateChannelName] = res.Value + // Move to state 2 c.JSON(http.StatusOK, iwfidl.WorkflowStateDecideResponse{ StateDecision: &iwfidl.StateDecision{ NextStates: []iwfidl.StateMovement{ @@ -244,7 +258,7 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { }) return } else if req.GetWorkflowStateId() == State2 { - // go to complete + // Move to completion c.JSON(http.StatusOK, iwfidl.WorkflowStateDecideResponse{ StateDecision: &iwfidl.StateDecision{ NextStates: []iwfidl.StateMovement{ diff --git a/integ/workflow/signal/routers.go b/integ/workflow/signal/routers.go index b978e442..1c39c5b7 100644 --- a/integ/workflow/signal/routers.go +++ b/integ/workflow/signal/routers.go @@ -12,6 +12,16 @@ import ( "net/http" ) +/** + * This test workflow has two states, using REST controller to implement the workflow directly. + * + * State1: + * - WaitUntil waits until 4 signals are received + * - Execute method publishes the 4 signals & moves to State2 + * State2: + * - WaitUntil method does nothing + * - Execute method will gracefully complete workflow + */ const ( WorkflowType = "signal" State1 = "S1" @@ -94,6 +104,7 @@ func (h *handler) ApiV1WorkflowStateStart(c *gin.Context) { if req.GetWorkflowType() == WorkflowType { h.invokeHistory[req.GetWorkflowStateId()+"_start"]++ if req.GetWorkflowStateId() == State1 { + // Proceed when 4 signals are received c.JSON(http.StatusOK, iwfidl.WorkflowStateStartResponse{ CommandRequest: &iwfidl.CommandRequest{ SignalCommands: []iwfidl.SignalCommand{ @@ -118,6 +129,7 @@ func (h *handler) ApiV1WorkflowStateStart(c *gin.Context) { return } if req.GetWorkflowStateId() == State2 { + // Go straight to the decide methods without any commands c.JSON(http.StatusOK, iwfidl.WorkflowStateStartResponse{ CommandRequest: &iwfidl.CommandRequest{ DeciderTriggerType: iwfidl.ALL_COMMAND_COMPLETED.Ptr(), @@ -142,6 +154,8 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { h.invokeHistory[req.GetWorkflowStateId()+"_decide"]++ if req.GetWorkflowStateId() == State1 { signalResults := req.GetCommandResults() + + // Publish 4 signals for i := 0; i < 4; i++ { signalId := signalResults.SignalResults[i].GetCommandId() signalValue := signalResults.SignalResults[i].GetSignalValue() @@ -150,6 +164,7 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { h.invokeData[fmt.Sprintf("signalValue%v", i)] = signalValue } + // Move to State 2 c.JSON(http.StatusOK, iwfidl.WorkflowStateDecideResponse{ StateDecision: &iwfidl.StateDecision{ NextStates: []iwfidl.StateMovement{ @@ -162,7 +177,7 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { }) return } else if req.GetWorkflowStateId() == State2 { - // go to complete + // Move to completion c.JSON(http.StatusOK, iwfidl.WorkflowStateDecideResponse{ StateDecision: &iwfidl.StateDecision{ NextStates: []iwfidl.StateMovement{ diff --git a/integ/workflow/skipstart/routers.go b/integ/workflow/skipstart/routers.go index a502cd4b..3b9b4056 100644 --- a/integ/workflow/skipstart/routers.go +++ b/integ/workflow/skipstart/routers.go @@ -8,6 +8,16 @@ import ( "net/http" ) +/** + * This test workflow has 2 states, using REST controller to implement the workflow directly. + * + * State1: + * - Wait until is skipped. + * - Execute method will go to State2 + * State2: + * - Wait until is skipped. + * - Execute method will gracefully complete workflow + */ const ( WorkflowType = "skipstart" State1 = "S1" @@ -40,7 +50,7 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { if req.GetWorkflowType() == WorkflowType { h.invokeHistory[req.GetWorkflowStateId()+"_decide"]++ if req.GetWorkflowStateId() == State1 { - // go to S2 + // Move to State 2 with the provided input & options c.JSON(http.StatusOK, iwfidl.WorkflowStateDecideResponse{ StateDecision: &iwfidl.StateDecision{ NextStates: []iwfidl.StateMovement{ @@ -56,7 +66,7 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { }) return } else if req.GetWorkflowStateId() == State2 { - // go to complete + // Move to completion with the provided input c.JSON(http.StatusOK, iwfidl.WorkflowStateDecideResponse{ StateDecision: &iwfidl.StateDecision{ NextStates: []iwfidl.StateMovement{ diff --git a/integ/workflow/timer/routers.go b/integ/workflow/timer/routers.go index 62553c00..d324dadc 100644 --- a/integ/workflow/timer/routers.go +++ b/integ/workflow/timer/routers.go @@ -13,6 +13,16 @@ import ( "github.com/indeedeng/iwf/service" ) +/** + * This test workflow has 2 states, using REST controller to implement the workflow directly. + * + * State1: + * - Has 3 timers (10s, 1d, 1y) before executing state + * - Execute method will go to State2 + * State2: + * - Waits on nothing. Will execute momentarily + * - Execute method will gracefully complete workflow + */ const ( WorkflowType = "timer" State1 = "S1" @@ -49,6 +59,8 @@ func (h *handler) ApiV1WorkflowStateStart(c *gin.Context) { } now := int64(nowInt) h.invokeData["scheduled_at"] = now + + // Proceed after 3 timers complete c.JSON(http.StatusOK, iwfidl.WorkflowStateStartResponse{ CommandRequest: &iwfidl.CommandRequest{ TimerCommands: []iwfidl.TimerCommand{ @@ -70,6 +82,8 @@ func (h *handler) ApiV1WorkflowStateStart(c *gin.Context) { }) return } + + // Go straight to the decide methods without any commands if req.GetWorkflowStateId() == State2 { c.JSON(http.StatusOK, iwfidl.WorkflowStateStartResponse{ CommandRequest: &iwfidl.CommandRequest{ @@ -99,6 +113,7 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { timerResults := req.GetCommandResults() timerId := timerResults.GetTimerResults()[0].GetCommandId() h.invokeData["timer_id"] = timerId + // Move to State 2 c.JSON(http.StatusOK, iwfidl.WorkflowStateDecideResponse{ StateDecision: &iwfidl.StateDecision{ NextStates: []iwfidl.StateMovement{ @@ -110,7 +125,7 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { }) return } else if req.GetWorkflowStateId() == State2 { - // go to complete + // Move to completion c.JSON(http.StatusOK, iwfidl.WorkflowStateDecideResponse{ StateDecision: &iwfidl.StateDecision{ NextStates: []iwfidl.StateMovement{ diff --git a/integ/workflow/wait_for_state_completion/routers.go b/integ/workflow/wait_for_state_completion/routers.go index 7b5a2b59..41b8c19b 100644 --- a/integ/workflow/wait_for_state_completion/routers.go +++ b/integ/workflow/wait_for_state_completion/routers.go @@ -13,6 +13,16 @@ import ( "github.com/indeedeng/iwf/service" ) +/** + * This test workflow has 2 states, using REST controller to implement the workflow directly. + * + * State1: + * - 10-second delay is added before executing state + * - Execute method will go to State2 + * State2: + * - Waits on nothing. Will execute momentarily + * - Execute method will gracefully complete workflow + */ const ( WorkflowType = "wait_for_state_completion" State1 = "S1" @@ -49,6 +59,7 @@ func (h *handler) ApiV1WorkflowStateStart(c *gin.Context) { } now := int64(nowInt) h.invokeData["scheduled_at"] = now + // Proceed after 10s c.JSON(http.StatusOK, iwfidl.WorkflowStateStartResponse{ CommandRequest: &iwfidl.CommandRequest{ TimerCommands: []iwfidl.TimerCommand{ @@ -62,6 +73,8 @@ func (h *handler) ApiV1WorkflowStateStart(c *gin.Context) { }) return } + + // Go straight to the decide methods without any commands if req.GetWorkflowStateId() == State2 { c.JSON(http.StatusOK, iwfidl.WorkflowStateStartResponse{ CommandRequest: &iwfidl.CommandRequest{ @@ -91,6 +104,7 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { timerResults := req.GetCommandResults() timerId := timerResults.GetTimerResults()[0].GetCommandId() h.invokeData["timer_id"] = timerId + // Move to State 2 c.JSON(http.StatusOK, iwfidl.WorkflowStateDecideResponse{ StateDecision: &iwfidl.StateDecision{ NextStates: []iwfidl.StateMovement{ @@ -103,7 +117,7 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { }) return } else if req.GetWorkflowStateId() == State2 { - // go to complete + // Move to completion c.JSON(http.StatusOK, iwfidl.WorkflowStateDecideResponse{ StateDecision: &iwfidl.StateDecision{ NextStates: []iwfidl.StateMovement{ diff --git a/integ/workflow/wait_until_search_attributes/routers.go b/integ/workflow/wait_until_search_attributes/routers.go index 78aa9a8f..f4ce6866 100644 --- a/integ/workflow/wait_until_search_attributes/routers.go +++ b/integ/workflow/wait_until_search_attributes/routers.go @@ -18,7 +18,7 @@ import ( * - Execute method will go to State2 * State2: * - Waits on nothing. Will execute momentarily - * - Skips wait unit + * - Skips wait until * - 10-second delay is added before executing state * - Execute method will gracefully complete workflow */ @@ -51,6 +51,7 @@ func (h *handler) ApiV1WorkflowStateStart(c *gin.Context) { if req.GetWorkflowType() == WorkflowType { h.invokeHistory[req.GetWorkflowStateId()+"_start"]++ if req.GetWorkflowStateId() == State1 { + // Go straight to the decide methods without any commands c.JSON(http.StatusOK, iwfidl.WorkflowStateStartResponse{ CommandRequest: &iwfidl.CommandRequest{ DeciderTriggerType: iwfidl.ALL_COMMAND_COMPLETED.Ptr(), @@ -59,6 +60,7 @@ func (h *handler) ApiV1WorkflowStateStart(c *gin.Context) { return } if req.GetWorkflowStateId() == State2 { + // Go straight to the decide methods without any commands c.JSON(http.StatusOK, iwfidl.WorkflowStateStartResponse{ CommandRequest: &iwfidl.CommandRequest{ DeciderTriggerType: iwfidl.ALL_COMMAND_COMPLETED.Ptr(), @@ -82,6 +84,7 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { if req.GetWorkflowType() == WorkflowType { h.invokeHistory[req.GetWorkflowStateId()+"_decide"]++ if req.GetWorkflowStateId() == State1 { + // Move to State 2, skipping wait until c.JSON(http.StatusOK, iwfidl.WorkflowStateDecideResponse{ StateDecision: &iwfidl.StateDecision{ NextStates: []iwfidl.StateMovement{ @@ -97,6 +100,7 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { return } else if req.GetWorkflowStateId() == State2 { time.Sleep(time.Second * 10) + // Move to completion c.JSON(http.StatusOK, iwfidl.WorkflowStateDecideResponse{ StateDecision: &iwfidl.StateDecision{ NextStates: []iwfidl.StateMovement{ diff --git a/integ/workflow/wait_until_search_attributes_optimization/routers.go b/integ/workflow/wait_until_search_attributes_optimization/routers.go index b7a2230b..67c32cc6 100644 --- a/integ/workflow/wait_until_search_attributes_optimization/routers.go +++ b/integ/workflow/wait_until_search_attributes_optimization/routers.go @@ -69,23 +69,9 @@ func (h *handler) ApiV1WorkflowStateStart(c *gin.Context) { if req.GetWorkflowType() == WorkflowType { h.invokeHistory[req.GetWorkflowStateId()+"_start"]++ - if req.GetWorkflowStateId() == State1 { - c.JSON(http.StatusOK, iwfidl.WorkflowStateStartResponse{ - CommandRequest: &iwfidl.CommandRequest{ - DeciderTriggerType: iwfidl.ALL_COMMAND_COMPLETED.Ptr(), - }, - }) - return - } - if req.GetWorkflowStateId() == State2 { - c.JSON(http.StatusOK, iwfidl.WorkflowStateStartResponse{ - CommandRequest: &iwfidl.CommandRequest{ - DeciderTriggerType: iwfidl.ALL_COMMAND_COMPLETED.Ptr(), - }, - }) - return - } - if req.GetWorkflowStateId() == State3 { + if req.GetWorkflowStateId() == State1 || req.GetWorkflowStateId() == State2 || req.GetWorkflowStateId() == State3 || + req.GetWorkflowStateId() == State5 || req.GetWorkflowStateId() == State6 || req.GetWorkflowStateId() == State7 { + // Go straight to the decide methods without any commands c.JSON(http.StatusOK, iwfidl.WorkflowStateStartResponse{ CommandRequest: &iwfidl.CommandRequest{ DeciderTriggerType: iwfidl.ALL_COMMAND_COMPLETED.Ptr(), @@ -94,6 +80,7 @@ func (h *handler) ApiV1WorkflowStateStart(c *gin.Context) { return } if req.GetWorkflowStateId() == State4 { + // Proceed after signal is received c.JSON(http.StatusOK, iwfidl.WorkflowStateStartResponse{ CommandRequest: &iwfidl.CommandRequest{ DeciderTriggerType: iwfidl.ALL_COMMAND_COMPLETED.Ptr(), @@ -107,30 +94,6 @@ func (h *handler) ApiV1WorkflowStateStart(c *gin.Context) { }) return } - if req.GetWorkflowStateId() == State5 { - c.JSON(http.StatusOK, iwfidl.WorkflowStateStartResponse{ - CommandRequest: &iwfidl.CommandRequest{ - DeciderTriggerType: iwfidl.ALL_COMMAND_COMPLETED.Ptr(), - }, - }) - return - } - if req.GetWorkflowStateId() == State6 { - c.JSON(http.StatusOK, iwfidl.WorkflowStateStartResponse{ - CommandRequest: &iwfidl.CommandRequest{ - DeciderTriggerType: iwfidl.ALL_COMMAND_COMPLETED.Ptr(), - }, - }) - return - } - if req.GetWorkflowStateId() == State7 { - c.JSON(http.StatusOK, iwfidl.WorkflowStateStartResponse{ - CommandRequest: &iwfidl.CommandRequest{ - DeciderTriggerType: iwfidl.ALL_COMMAND_COMPLETED.Ptr(), - }, - }) - return - } } c.JSON(http.StatusBadRequest, struct{}{}) @@ -149,6 +112,7 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { if req.GetWorkflowStateId() == State1 { context := req.GetContext() if context.GetStateExecutionId() == "S1-5" { + // Move to State 2 c.JSON(http.StatusOK, iwfidl.WorkflowStateDecideResponse{ StateDecision: &iwfidl.StateDecision{ NextStates: []iwfidl.StateMovement{ @@ -162,6 +126,7 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { }, }) } else { + // Repeat State 1 (5 times) time.Sleep(time.Second * 1) c.JSON(http.StatusOK, iwfidl.WorkflowStateDecideResponse{ StateDecision: &iwfidl.StateDecision{ @@ -177,6 +142,7 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { } else if req.GetWorkflowStateId() == State2 { context := req.GetContext() if context.GetStateExecutionId() == "S2-2" { + // Move to State 3 & 4 c.JSON(http.StatusOK, iwfidl.WorkflowStateDecideResponse{ StateDecision: &iwfidl.StateDecision{ NextStates: []iwfidl.StateMovement{ @@ -190,6 +156,7 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { }, }) } else { + // Repeat State 2 and Move to State 3 c.JSON(http.StatusOK, iwfidl.WorkflowStateDecideResponse{ StateDecision: &iwfidl.StateDecision{ NextStates: []iwfidl.StateMovement{ @@ -209,6 +176,7 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { return } else if req.GetWorkflowStateId() == State3 { time.Sleep(time.Second * 8) + // Move to Completion c.JSON(http.StatusOK, iwfidl.WorkflowStateDecideResponse{ StateDecision: &iwfidl.StateDecision{ NextStates: []iwfidl.StateMovement{ @@ -220,6 +188,7 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { }) return } else if req.GetWorkflowStateId() == State4 { + // Move to State 5, skipping wait until c.JSON(http.StatusOK, iwfidl.WorkflowStateDecideResponse{ StateDecision: &iwfidl.StateDecision{ NextStates: []iwfidl.StateMovement{ @@ -234,6 +203,7 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { }) return } else if req.GetWorkflowStateId() == State5 { + // Move to State 6 and State 7 skipping wait until for 7 c.JSON(http.StatusOK, iwfidl.WorkflowStateDecideResponse{ StateDecision: &iwfidl.StateDecision{ NextStates: []iwfidl.StateMovement{ @@ -252,6 +222,7 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { return } else if req.GetWorkflowStateId() == State6 { time.Sleep(time.Second * 4) + // Move to completion c.JSON(http.StatusOK, iwfidl.WorkflowStateDecideResponse{ StateDecision: &iwfidl.StateDecision{ NextStates: []iwfidl.StateMovement{ @@ -263,6 +234,7 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { }) return } else if req.GetWorkflowStateId() == State7 { + // Move to completion c.JSON(http.StatusOK, iwfidl.WorkflowStateDecideResponse{ StateDecision: &iwfidl.StateDecision{ NextStates: []iwfidl.StateMovement{ diff --git a/integ/workflow/wf_execute_api_fail_and_proceed/routers.go b/integ/workflow/wf_execute_api_fail_and_proceed/routers.go index 1975d235..6ec3a201 100644 --- a/integ/workflow/wf_execute_api_fail_and_proceed/routers.go +++ b/integ/workflow/wf_execute_api_fail_and_proceed/routers.go @@ -10,6 +10,15 @@ import ( "github.com/indeedeng/iwf/integ/workflow/common" ) +/** + * This test workflow has one state, using REST controller to implement the workflow directly. + * + * State1: + * - WaitUntil method is skipped + * - Execute method will intentionally fail + * StateRecover: + * - Execute method will gracefully complete workflow + */ const ( WorkflowType = "wf_execute_api_fail_and_proceed" State1 = "S1" @@ -57,6 +66,7 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { } if req.WorkflowStateId == StateRecover { if input.GetData() == InputData && input.GetEncoding() == InputDataEncoding { + // Move to completion c.JSON(http.StatusOK, iwfidl.WorkflowStateDecideResponse{ StateDecision: &iwfidl.StateDecision{ NextStates: []iwfidl.StateMovement{ diff --git a/integ/workflow/wf_force_fail/routers.go b/integ/workflow/wf_force_fail/routers.go index cbf03cb4..107cbce7 100644 --- a/integ/workflow/wf_force_fail/routers.go +++ b/integ/workflow/wf_force_fail/routers.go @@ -9,6 +9,13 @@ import ( "net/http" ) +/** + * This test workflow has one state, using REST controller to implement the workflow directly. + * + * State1: + * - WaitUntil method does nothing + * - Execute method will intentionally force-fail + */ const ( WorkflowType = "wf_force_fail" State1 = "S1" @@ -42,6 +49,7 @@ func (h *handler) ApiV1WorkflowStateStart(c *gin.Context) { if req.GetWorkflowType() == WorkflowType { h.invokeHistory[req.GetWorkflowStateId()+"_start"]++ if req.GetWorkflowStateId() == State1 { + // Empty response c.JSON(http.StatusOK, iwfidl.WorkflowStateStartResponse{}) return } @@ -60,7 +68,7 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { if req.GetWorkflowType() == WorkflowType && req.GetWorkflowStateId() == State1 { h.invokeHistory[req.GetWorkflowStateId()+"_decide"]++ - // go to complete + // Force fail c.JSON(http.StatusOK, iwfidl.WorkflowStateDecideResponse{ StateDecision: &iwfidl.StateDecision{ NextStates: []iwfidl.StateMovement{ diff --git a/integ/workflow/wf_state_api_fail/routers.go b/integ/workflow/wf_state_api_fail/routers.go index e27de8a3..10571fa1 100644 --- a/integ/workflow/wf_state_api_fail/routers.go +++ b/integ/workflow/wf_state_api_fail/routers.go @@ -8,6 +8,12 @@ import ( "net/http" ) +/** + * This test workflow has one state, using REST controller to implement the workflow directly. + * + * State1: + * - The state will fail and exit + */ const ( WorkflowType = "wf_state_api_fail" State1 = "S1" @@ -36,6 +42,7 @@ func (h *handler) ApiV1WorkflowStateStart(c *gin.Context) { if req.GetWorkflowType() == WorkflowType { h.invokeHistory[req.GetWorkflowStateId()+"_start"]++ if req.GetWorkflowStateId() == State1 { + // Bad Request response c.JSON(http.StatusBadRequest, iwfidl.WorkflowStateStartResponse{}) return } diff --git a/integ/workflow/wf_state_api_fail_and_proceed/routers.go b/integ/workflow/wf_state_api_fail_and_proceed/routers.go index 1ebdcf08..4109f2d8 100644 --- a/integ/workflow/wf_state_api_fail_and_proceed/routers.go +++ b/integ/workflow/wf_state_api_fail_and_proceed/routers.go @@ -10,6 +10,12 @@ import ( "github.com/indeedeng/iwf/integ/workflow/common" ) +/** + * This test workflow has one state, using REST controller to implement the workflow directly. + * + * State1: + * - The state will fail and proceed to StateRecover which will gracefully complete workflow + */ const ( WorkflowType = "wf_state_api_fail_and_proceed" State1 = "S1" @@ -38,6 +44,7 @@ func (h *handler) ApiV1WorkflowStateStart(c *gin.Context) { if req.GetWorkflowType() == WorkflowType { h.invokeHistory[req.GetWorkflowStateId()+"_start"]++ if req.GetWorkflowStateId() == State1 { + // Bad Request response c.JSON(http.StatusBadRequest, iwfidl.WorkflowStateStartResponse{}) return } @@ -61,6 +68,7 @@ func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) { if req.GetWorkflowType() == WorkflowType { h.invokeHistory[req.GetWorkflowStateId()+"_decide"]++ } + // Move to completion c.JSON(http.StatusOK, iwfidl.WorkflowStateDecideResponse{ StateDecision: &iwfidl.StateDecision{ NextStates: []iwfidl.StateMovement{ diff --git a/integ/workflow/wf_state_api_timeout/routers.go b/integ/workflow/wf_state_api_timeout/routers.go index e194ffed..09172f8e 100644 --- a/integ/workflow/wf_state_api_timeout/routers.go +++ b/integ/workflow/wf_state_api_timeout/routers.go @@ -9,6 +9,13 @@ import ( "time" ) +/** + * This test workflow has one state, using REST controller to implement the workflow directly. + * + * State1: + * - Timeout is set for 10s + * - Waits for 30s to invoke a timeout exception + */ const ( WorkflowType = "wf_state_api_timeout" State1 = "S1" @@ -37,7 +44,9 @@ func (h *handler) ApiV1WorkflowStateStart(c *gin.Context) { if req.GetWorkflowType() == WorkflowType { h.invokeHistory[req.GetWorkflowStateId()+"_start"]++ if req.GetWorkflowStateId() == State1 { + // Sleep for longer than the timeout time.Sleep(time.Second * 30) + // Bad Request response c.JSON(http.StatusBadRequest, iwfidl.WorkflowStateStartResponse{}) return } diff --git a/integ/workflow/wf_state_options_data_attributes_loading/routers.go b/integ/workflow/wf_state_options_data_attributes_loading/routers.go index dd0c0af4..d765ed0a 100644 --- a/integ/workflow/wf_state_options_data_attributes_loading/routers.go +++ b/integ/workflow/wf_state_options_data_attributes_loading/routers.go @@ -75,7 +75,7 @@ func (h *handler) ApiV1WorkflowStateStart(c *gin.Context) { loadingTypeFromInput := req.GetStateInput() loadingType := iwfidl.PersistenceLoadingType(loadingTypeFromInput.GetData()) - if req.GetWorkflowStateId() == State2 { + if req.GetWorkflowStateId() == State2 || req.GetWorkflowStateId() == State4 || req.GetWorkflowStateId() == State5 { verifyLoadedDataAttributes(req.GetWorkflowStateId(), currentMethod, req.GetDataObjects(), loadingType) } @@ -83,14 +83,7 @@ func (h *handler) ApiV1WorkflowStateStart(c *gin.Context) { verifyEmptyDataAttributes(req.GetDataObjects()) } - if req.GetWorkflowStateId() == State4 { - verifyLoadedDataAttributes(req.GetWorkflowStateId(), currentMethod, req.GetDataObjects(), loadingType) - } - - if req.GetWorkflowStateId() == State5 { - verifyLoadedDataAttributes(req.GetWorkflowStateId(), currentMethod, req.GetDataObjects(), loadingType) - } - + // Go straight to the decide methods without any commands c.JSON(http.StatusOK, iwfidl.WorkflowStateStartResponse{ CommandRequest: &iwfidl.CommandRequest{ DeciderTriggerType: iwfidl.ANY_COMMAND_COMPLETED.Ptr(), @@ -148,6 +141,7 @@ func getState1DecideResponse(req iwfidl.WorkflowStateDecideRequest) iwfidl.Workf loadingType := iwfidl.PersistenceLoadingType(loadingTypeFromInput.GetData()) noneLoadingType := iwfidl.NONE + // Move to State 2 with provided options & input after updating data objects return iwfidl.WorkflowStateDecideResponse{ StateDecision: &iwfidl.StateDecision{ NextStates: []iwfidl.StateMovement{ @@ -175,6 +169,7 @@ func getState2DecideResponse(req iwfidl.WorkflowStateDecideRequest) iwfidl.Workf loadingType := iwfidl.PersistenceLoadingType(loadingTypeFromInput.GetData()) noneLoadingType := iwfidl.NONE + // Move to State 3 with provided options & input return iwfidl.WorkflowStateDecideResponse{ StateDecision: &iwfidl.StateDecision{ NextStates: []iwfidl.StateMovement{ @@ -200,6 +195,7 @@ func getState3DecideResponse(req iwfidl.WorkflowStateDecideRequest) iwfidl.Workf loadingTypeFromInput := req.GetStateInput() loadingType := iwfidl.PersistenceLoadingType(loadingTypeFromInput.GetData()) + // Move to State 4 with provided options & input return iwfidl.WorkflowStateDecideResponse{ StateDecision: &iwfidl.StateDecision{ NextStates: []iwfidl.StateMovement{ @@ -222,6 +218,7 @@ func getState4DecideResponse(req iwfidl.WorkflowStateDecideRequest) iwfidl.Workf loadingTypeFromInput := req.GetStateInput() loadingType := iwfidl.PersistenceLoadingType(loadingTypeFromInput.GetData()) + // Move to State 5 with provided options & input return iwfidl.WorkflowStateDecideResponse{ StateDecision: &iwfidl.StateDecision{ NextStates: []iwfidl.StateMovement{ @@ -245,6 +242,7 @@ func getState4DecideResponse(req iwfidl.WorkflowStateDecideRequest) iwfidl.Workf } func getState5DecideResponse() iwfidl.WorkflowStateDecideResponse { + // Move to completion return iwfidl.WorkflowStateDecideResponse{ StateDecision: &iwfidl.StateDecision{ NextStates: []iwfidl.StateMovement{ diff --git a/integ/workflow/wf_state_options_search_attributes_loading/routers.go b/integ/workflow/wf_state_options_search_attributes_loading/routers.go index 6dd87fd6..e3fe6575 100644 --- a/integ/workflow/wf_state_options_search_attributes_loading/routers.go +++ b/integ/workflow/wf_state_options_search_attributes_loading/routers.go @@ -12,7 +12,7 @@ import ( ) /** - * This test workflow has four states, using REST controller to implement the workflow directly. + * This test workflow has five states, using REST controller to implement the workflow directly. * * State1: * - WaitUntil method does nothing @@ -76,7 +76,7 @@ func (h *handler) ApiV1WorkflowStateStart(c *gin.Context) { loadingTypeFromInput := req.GetStateInput() loadingType := iwfidl.PersistenceLoadingType(loadingTypeFromInput.GetData()) - if req.GetWorkflowStateId() == State2 { + if req.GetWorkflowStateId() == State2 || req.GetWorkflowStateId() == State4 || req.GetWorkflowStateId() == State5 { verifyLoadedSearchAttributes(req.GetWorkflowStateId(), currentMethod, req.GetSearchAttributes(), loadingType) } @@ -84,14 +84,7 @@ func (h *handler) ApiV1WorkflowStateStart(c *gin.Context) { verifyEmptySearchAttributes(req.GetSearchAttributes()) } - if req.GetWorkflowStateId() == State4 { - verifyLoadedSearchAttributes(req.GetWorkflowStateId(), currentMethod, req.GetSearchAttributes(), loadingType) - } - - if req.GetWorkflowStateId() == State5 { - verifyLoadedSearchAttributes(req.GetWorkflowStateId(), currentMethod, req.GetSearchAttributes(), loadingType) - } - + // Go straight to the decide methods without any commands c.JSON(http.StatusOK, iwfidl.WorkflowStateStartResponse{ CommandRequest: &iwfidl.CommandRequest{ DeciderTriggerType: iwfidl.ANY_COMMAND_COMPLETED.Ptr(), @@ -149,6 +142,7 @@ func getState1DecideResponse(req iwfidl.WorkflowStateDecideRequest) iwfidl.Workf loadingType := iwfidl.PersistenceLoadingType(loadingTypeFromInput.GetData()) noneLoadingType := iwfidl.NONE + // Move to State 2 with the provided options & input after updating data objects return iwfidl.WorkflowStateDecideResponse{ StateDecision: &iwfidl.StateDecision{ NextStates: []iwfidl.StateMovement{ @@ -176,6 +170,7 @@ func getState2DecideResponse(req iwfidl.WorkflowStateDecideRequest) iwfidl.Workf loadingType := iwfidl.PersistenceLoadingType(loadingTypeFromInput.GetData()) noneLoadingType := iwfidl.NONE + // Move to State 3 with the provided options & input return iwfidl.WorkflowStateDecideResponse{ StateDecision: &iwfidl.StateDecision{ NextStates: []iwfidl.StateMovement{ @@ -201,6 +196,7 @@ func getState3DecideResponse(req iwfidl.WorkflowStateDecideRequest) iwfidl.Workf loadingTypeFromInput := req.GetStateInput() loadingType := iwfidl.PersistenceLoadingType(loadingTypeFromInput.GetData()) + // Move to State 4 with the provided options & input return iwfidl.WorkflowStateDecideResponse{ StateDecision: &iwfidl.StateDecision{ NextStates: []iwfidl.StateMovement{ @@ -223,6 +219,7 @@ func getState4DecideResponse(req iwfidl.WorkflowStateDecideRequest) iwfidl.Workf loadingTypeFromInput := req.GetStateInput() loadingType := iwfidl.PersistenceLoadingType(loadingTypeFromInput.GetData()) + // Move to State 5 with the provided options & input return iwfidl.WorkflowStateDecideResponse{ StateDecision: &iwfidl.StateDecision{ NextStates: []iwfidl.StateMovement{ @@ -246,6 +243,7 @@ func getState4DecideResponse(req iwfidl.WorkflowStateDecideRequest) iwfidl.Workf } func getState5DecideResponse() iwfidl.WorkflowStateDecideResponse { + // Move to completion return iwfidl.WorkflowStateDecideResponse{ StateDecision: &iwfidl.StateDecision{ NextStates: []iwfidl.StateMovement{