go.uber.org/cadence@v1.2.9/internal/internal_decision_state_machine.go (about)

     1  // Copyright (c) 2017 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all copies or substantial portions of the Software.
    12  //
    13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE.
    20  
    21  package internal
    22  
    23  import (
    24  	"container/list"
    25  	"fmt"
    26  
    27  	s "go.uber.org/cadence/.gen/go/shared"
    28  	"go.uber.org/cadence/internal/common"
    29  	"go.uber.org/cadence/internal/common/util"
    30  )
    31  
    32  type (
    33  	decisionState int32
    34  	decisionType  int32
    35  
    36  	decisionID struct {
    37  		decisionType decisionType
    38  		id           string
    39  	}
    40  
    41  	decisionStateMachine interface {
    42  		getState() decisionState
    43  		getID() decisionID
    44  		isDone() bool
    45  		getDecision() *s.Decision // return nil if there is no decision in current state
    46  		cancel()
    47  
    48  		handleStartedEvent()
    49  		handleCancelInitiatedEvent()
    50  		handleCanceledEvent()
    51  		handleCancelFailedEvent()
    52  		handleCompletionEvent()
    53  		handleInitiationFailedEvent()
    54  		handleInitiatedEvent()
    55  
    56  		handleDecisionSent()
    57  
    58  		setData(data interface{})
    59  		getData() interface{}
    60  	}
    61  
    62  	decisionStateMachineBase struct {
    63  		id      decisionID
    64  		state   decisionState
    65  		history []string
    66  		data    interface{}
    67  		helper  *decisionsHelper
    68  	}
    69  
    70  	activityDecisionStateMachine struct {
    71  		*decisionStateMachineBase
    72  		attributes *s.ScheduleActivityTaskDecisionAttributes
    73  	}
    74  
    75  	timerDecisionStateMachine struct {
    76  		*decisionStateMachineBase
    77  		attributes *s.StartTimerDecisionAttributes
    78  		canceled   bool
    79  	}
    80  
    81  	childWorkflowDecisionStateMachine struct {
    82  		*decisionStateMachineBase
    83  		attributes *s.StartChildWorkflowExecutionDecisionAttributes
    84  	}
    85  
    86  	naiveDecisionStateMachine struct {
    87  		*decisionStateMachineBase
    88  		decision *s.Decision
    89  	}
    90  
    91  	// only possible state transition is: CREATED->SENT->INITIATED->COMPLETED
    92  	cancelExternalWorkflowDecisionStateMachine struct {
    93  		*naiveDecisionStateMachine
    94  	}
    95  
    96  	signalExternalWorkflowDecisionStateMachine struct {
    97  		*naiveDecisionStateMachine
    98  	}
    99  
   100  	// only possible state transition is: CREATED->SENT->COMPLETED
   101  	markerDecisionStateMachine struct {
   102  		*naiveDecisionStateMachine
   103  	}
   104  
   105  	upsertSearchAttributesDecisionStateMachine struct {
   106  		*naiveDecisionStateMachine
   107  	}
   108  
   109  	decisionsHelper struct {
   110  		orderedDecisions *list.List
   111  		decisions        map[decisionID]*list.Element
   112  
   113  		scheduledEventIDToActivityID     map[int64]string
   114  		scheduledEventIDToCancellationID map[int64]string
   115  		scheduledEventIDToSignalID       map[int64]string
   116  	}
   117  
   118  	// panic when decision state machine is in illegal state
   119  	stateMachineIllegalStatePanic struct {
   120  		message string
   121  	}
   122  )
   123  
   124  const (
   125  	decisionStateCreated                                decisionState = 0
   126  	decisionStateDecisionSent                           decisionState = 1
   127  	decisionStateCanceledBeforeInitiated                decisionState = 2
   128  	decisionStateInitiated                              decisionState = 3
   129  	decisionStateStarted                                decisionState = 4
   130  	decisionStateCanceledAfterInitiated                 decisionState = 5
   131  	decisionStateCanceledAfterStarted                   decisionState = 6
   132  	decisionStateCancellationDecisionSent               decisionState = 7
   133  	decisionStateCompletedAfterCancellationDecisionSent decisionState = 8
   134  	decisionStateCompleted                              decisionState = 9
   135  )
   136  
   137  const (
   138  	decisionTypeActivity               decisionType = 0
   139  	decisionTypeChildWorkflow          decisionType = 1
   140  	decisionTypeCancellation           decisionType = 2
   141  	decisionTypeMarker                 decisionType = 3
   142  	decisionTypeTimer                  decisionType = 4
   143  	decisionTypeSignal                 decisionType = 5
   144  	decisionTypeUpsertSearchAttributes decisionType = 6
   145  )
   146  
   147  const (
   148  	eventCancel           = "cancel"
   149  	eventDecisionSent     = "handleDecisionSent"
   150  	eventInitiated        = "handleInitiatedEvent"
   151  	eventInitiationFailed = "handleInitiationFailedEvent"
   152  	eventStarted          = "handleStartedEvent"
   153  	eventCompletion       = "handleCompletionEvent"
   154  	eventCancelInitiated  = "handleCancelInitiatedEvent"
   155  	eventCancelFailed     = "handleCancelFailedEvent"
   156  	eventCanceled         = "handleCanceledEvent"
   157  )
   158  
   159  const (
   160  	sideEffectMarkerName        = "SideEffect"
   161  	versionMarkerName           = "Version"
   162  	localActivityMarkerName     = "LocalActivity"
   163  	mutableSideEffectMarkerName = "MutableSideEffect"
   164  )
   165  
   166  func (d decisionState) String() string {
   167  	switch d {
   168  	case decisionStateCreated:
   169  		return "Created"
   170  	case decisionStateDecisionSent:
   171  		return "DecisionSent"
   172  	case decisionStateCanceledBeforeInitiated:
   173  		return "CanceledBeforeInitiated"
   174  	case decisionStateInitiated:
   175  		return "Initiated"
   176  	case decisionStateStarted:
   177  		return "Started"
   178  	case decisionStateCanceledAfterInitiated:
   179  		return "CanceledAfterInitiated"
   180  	case decisionStateCanceledAfterStarted:
   181  		return "CanceledAfterStarted"
   182  	case decisionStateCancellationDecisionSent:
   183  		return "CancellationDecisionSent"
   184  	case decisionStateCompletedAfterCancellationDecisionSent:
   185  		return "CompletedAfterCancellationDecisionSent"
   186  	case decisionStateCompleted:
   187  		return "Completed"
   188  	default:
   189  		return "Unknown"
   190  	}
   191  }
   192  
   193  func (d decisionType) String() string {
   194  	switch d {
   195  	case decisionTypeActivity:
   196  		return "Activity"
   197  	case decisionTypeChildWorkflow:
   198  		return "ChildWorkflow"
   199  	case decisionTypeCancellation:
   200  		return "Cancellation"
   201  	case decisionTypeMarker:
   202  		return "Marker"
   203  	case decisionTypeTimer:
   204  		return "Timer"
   205  	case decisionTypeSignal:
   206  		return "Signal"
   207  	default:
   208  		return "Unknown"
   209  	}
   210  }
   211  
   212  func (d decisionID) String() string {
   213  	return fmt.Sprintf("DecisionType: %v, ID: %v", d.decisionType, d.id)
   214  }
   215  
   216  func makeDecisionID(decisionType decisionType, id string) decisionID {
   217  	return decisionID{decisionType: decisionType, id: id}
   218  }
   219  
   220  func (h *decisionsHelper) newDecisionStateMachineBase(decisionType decisionType, id string) *decisionStateMachineBase {
   221  	return &decisionStateMachineBase{
   222  		id:      makeDecisionID(decisionType, id),
   223  		state:   decisionStateCreated,
   224  		history: []string{decisionStateCreated.String()},
   225  		helper:  h,
   226  	}
   227  }
   228  
   229  func (h *decisionsHelper) newActivityDecisionStateMachine(attributes *s.ScheduleActivityTaskDecisionAttributes) *activityDecisionStateMachine {
   230  	base := h.newDecisionStateMachineBase(decisionTypeActivity, attributes.GetActivityId())
   231  	return &activityDecisionStateMachine{
   232  		decisionStateMachineBase: base,
   233  		attributes:               attributes,
   234  	}
   235  }
   236  
   237  func (h *decisionsHelper) newTimerDecisionStateMachine(attributes *s.StartTimerDecisionAttributes) *timerDecisionStateMachine {
   238  	base := h.newDecisionStateMachineBase(decisionTypeTimer, attributes.GetTimerId())
   239  	return &timerDecisionStateMachine{
   240  		decisionStateMachineBase: base,
   241  		attributes:               attributes,
   242  	}
   243  }
   244  
   245  func (h *decisionsHelper) newChildWorkflowDecisionStateMachine(attributes *s.StartChildWorkflowExecutionDecisionAttributes) *childWorkflowDecisionStateMachine {
   246  	base := h.newDecisionStateMachineBase(decisionTypeChildWorkflow, attributes.GetWorkflowId())
   247  	return &childWorkflowDecisionStateMachine{
   248  		decisionStateMachineBase: base,
   249  		attributes:               attributes,
   250  	}
   251  }
   252  
   253  func (h *decisionsHelper) newNaiveDecisionStateMachine(decisionType decisionType, id string, decision *s.Decision) *naiveDecisionStateMachine {
   254  	base := h.newDecisionStateMachineBase(decisionType, id)
   255  	return &naiveDecisionStateMachine{
   256  		decisionStateMachineBase: base,
   257  		decision:                 decision,
   258  	}
   259  }
   260  
   261  func (h *decisionsHelper) newMarkerDecisionStateMachine(id string, attributes *s.RecordMarkerDecisionAttributes) *markerDecisionStateMachine {
   262  	d := createNewDecision(s.DecisionTypeRecordMarker)
   263  	d.RecordMarkerDecisionAttributes = attributes
   264  	return &markerDecisionStateMachine{
   265  		naiveDecisionStateMachine: h.newNaiveDecisionStateMachine(decisionTypeMarker, id, d),
   266  	}
   267  }
   268  
   269  func (h *decisionsHelper) newCancelExternalWorkflowStateMachine(attributes *s.RequestCancelExternalWorkflowExecutionDecisionAttributes, cancellationID string) *cancelExternalWorkflowDecisionStateMachine {
   270  	d := createNewDecision(s.DecisionTypeRequestCancelExternalWorkflowExecution)
   271  	d.RequestCancelExternalWorkflowExecutionDecisionAttributes = attributes
   272  	return &cancelExternalWorkflowDecisionStateMachine{
   273  		naiveDecisionStateMachine: h.newNaiveDecisionStateMachine(decisionTypeCancellation, cancellationID, d),
   274  	}
   275  }
   276  
   277  func (h *decisionsHelper) newSignalExternalWorkflowStateMachine(attributes *s.SignalExternalWorkflowExecutionDecisionAttributes, signalID string) *signalExternalWorkflowDecisionStateMachine {
   278  	d := createNewDecision(s.DecisionTypeSignalExternalWorkflowExecution)
   279  	d.SignalExternalWorkflowExecutionDecisionAttributes = attributes
   280  	return &signalExternalWorkflowDecisionStateMachine{
   281  		naiveDecisionStateMachine: h.newNaiveDecisionStateMachine(decisionTypeSignal, signalID, d),
   282  	}
   283  }
   284  
   285  func (h *decisionsHelper) newUpsertSearchAttributesStateMachine(attributes *s.UpsertWorkflowSearchAttributesDecisionAttributes, upsertID string) *upsertSearchAttributesDecisionStateMachine {
   286  	d := createNewDecision(s.DecisionTypeUpsertWorkflowSearchAttributes)
   287  	d.UpsertWorkflowSearchAttributesDecisionAttributes = attributes
   288  	return &upsertSearchAttributesDecisionStateMachine{
   289  		naiveDecisionStateMachine: h.newNaiveDecisionStateMachine(decisionTypeUpsertSearchAttributes, upsertID, d),
   290  	}
   291  }
   292  
   293  func (d *decisionStateMachineBase) getState() decisionState {
   294  	return d.state
   295  }
   296  
   297  func (d *decisionStateMachineBase) getID() decisionID {
   298  	return d.id
   299  }
   300  
   301  func (d *decisionStateMachineBase) isDone() bool {
   302  	return d.state == decisionStateCompleted || d.state == decisionStateCompletedAfterCancellationDecisionSent
   303  }
   304  
   305  func (d *decisionStateMachineBase) setData(data interface{}) {
   306  	d.data = data
   307  }
   308  
   309  func (d *decisionStateMachineBase) getData() interface{} {
   310  	return d.data
   311  }
   312  
   313  func (d *decisionStateMachineBase) moveState(newState decisionState, event string) {
   314  	d.history = append(d.history, event)
   315  	d.state = newState
   316  	d.history = append(d.history, newState.String())
   317  
   318  	if newState == decisionStateCompleted {
   319  		if elem, ok := d.helper.decisions[d.getID()]; ok {
   320  			d.helper.orderedDecisions.Remove(elem)
   321  			delete(d.helper.decisions, d.getID())
   322  		}
   323  	}
   324  }
   325  
   326  func (d stateMachineIllegalStatePanic) String() string {
   327  	return d.message
   328  }
   329  
   330  func panicIllegalState(message string) {
   331  	panic(stateMachineIllegalStatePanic{message: message})
   332  }
   333  
   334  func (d *decisionStateMachineBase) failStateTransition(event string) {
   335  	// this is when we detect illegal state transition, likely due to ill history sequence or nondeterministic decider code
   336  	panicIllegalState(fmt.Sprintf("invalid state transition: attempt to %v, %v", event, d))
   337  }
   338  
   339  func (d *decisionStateMachineBase) handleDecisionSent() {
   340  	switch d.state {
   341  	case decisionStateCreated:
   342  		d.moveState(decisionStateDecisionSent, eventDecisionSent)
   343  	}
   344  }
   345  
   346  func (d *decisionStateMachineBase) cancel() {
   347  	switch d.state {
   348  	case decisionStateCompleted, decisionStateCompletedAfterCancellationDecisionSent:
   349  		// No op. This is legit. People could cancel context after timer/activity is done.
   350  	case decisionStateCreated:
   351  		d.moveState(decisionStateCompleted, eventCancel)
   352  	case decisionStateDecisionSent:
   353  		d.moveState(decisionStateCanceledBeforeInitiated, eventCancel)
   354  	case decisionStateInitiated:
   355  		d.moveState(decisionStateCanceledAfterInitiated, eventCancel)
   356  	default:
   357  		d.failStateTransition(eventCancel)
   358  	}
   359  }
   360  
   361  func (d *decisionStateMachineBase) handleInitiatedEvent() {
   362  	switch d.state {
   363  	case decisionStateDecisionSent:
   364  		d.moveState(decisionStateInitiated, eventInitiated)
   365  	case decisionStateCanceledBeforeInitiated:
   366  		d.moveState(decisionStateCanceledAfterInitiated, eventInitiated)
   367  	default:
   368  		d.failStateTransition(eventInitiated)
   369  	}
   370  }
   371  
   372  func (d *decisionStateMachineBase) handleInitiationFailedEvent() {
   373  	switch d.state {
   374  	case decisionStateInitiated, decisionStateDecisionSent, decisionStateCanceledBeforeInitiated:
   375  		d.moveState(decisionStateCompleted, eventInitiationFailed)
   376  	default:
   377  		d.failStateTransition(eventInitiationFailed)
   378  	}
   379  }
   380  
   381  func (d *decisionStateMachineBase) handleStartedEvent() {
   382  	d.history = append(d.history, eventStarted)
   383  }
   384  
   385  func (d *decisionStateMachineBase) handleCompletionEvent() {
   386  	switch d.state {
   387  	case decisionStateCanceledAfterInitiated, decisionStateInitiated:
   388  		d.moveState(decisionStateCompleted, eventCompletion)
   389  	case decisionStateCancellationDecisionSent:
   390  		d.moveState(decisionStateCompletedAfterCancellationDecisionSent, eventCompletion)
   391  	default:
   392  		d.failStateTransition(eventCompletion)
   393  	}
   394  }
   395  
   396  func (d *decisionStateMachineBase) handleCancelInitiatedEvent() {
   397  	d.history = append(d.history, eventCancelInitiated)
   398  	switch d.state {
   399  	case decisionStateCancellationDecisionSent:
   400  	// No state change
   401  	default:
   402  		d.failStateTransition(eventCancelInitiated)
   403  	}
   404  }
   405  
   406  func (d *decisionStateMachineBase) handleCancelFailedEvent() {
   407  	switch d.state {
   408  	case decisionStateCompletedAfterCancellationDecisionSent:
   409  		d.moveState(decisionStateCompleted, eventCancelFailed)
   410  	default:
   411  		d.failStateTransition(eventCancelFailed)
   412  	}
   413  }
   414  
   415  func (d *decisionStateMachineBase) handleCanceledEvent() {
   416  	switch d.state {
   417  	case decisionStateCancellationDecisionSent:
   418  		d.moveState(decisionStateCompleted, eventCanceled)
   419  	default:
   420  		d.failStateTransition(eventCanceled)
   421  	}
   422  }
   423  
   424  func (d *decisionStateMachineBase) String() string {
   425  	return fmt.Sprintf("%v, state=%v, isDone()=%v, history=%v",
   426  		d.id, d.state, d.isDone(), d.history)
   427  }
   428  
   429  func (d *activityDecisionStateMachine) getDecision() *s.Decision {
   430  	switch d.state {
   431  	case decisionStateCreated:
   432  		decision := createNewDecision(s.DecisionTypeScheduleActivityTask)
   433  		decision.ScheduleActivityTaskDecisionAttributes = d.attributes
   434  		return decision
   435  	case decisionStateCanceledAfterInitiated:
   436  		decision := createNewDecision(s.DecisionTypeRequestCancelActivityTask)
   437  		decision.RequestCancelActivityTaskDecisionAttributes = &s.RequestCancelActivityTaskDecisionAttributes{
   438  			ActivityId: d.attributes.ActivityId,
   439  		}
   440  		return decision
   441  	default:
   442  		return nil
   443  	}
   444  }
   445  
   446  func (d *activityDecisionStateMachine) handleDecisionSent() {
   447  	switch d.state {
   448  	case decisionStateCanceledAfterInitiated:
   449  		d.moveState(decisionStateCancellationDecisionSent, eventDecisionSent)
   450  	default:
   451  		d.decisionStateMachineBase.handleDecisionSent()
   452  	}
   453  }
   454  
   455  func (d *activityDecisionStateMachine) handleCancelFailedEvent() {
   456  	switch d.state {
   457  	case decisionStateCancellationDecisionSent:
   458  		d.moveState(decisionStateInitiated, eventCancelFailed)
   459  	default:
   460  		d.decisionStateMachineBase.handleCancelFailedEvent()
   461  	}
   462  }
   463  
   464  func (d *timerDecisionStateMachine) cancel() {
   465  	d.canceled = true
   466  	d.decisionStateMachineBase.cancel()
   467  }
   468  
   469  func (d *timerDecisionStateMachine) isDone() bool {
   470  	return d.state == decisionStateCompleted || d.canceled
   471  }
   472  
   473  func (d *timerDecisionStateMachine) handleDecisionSent() {
   474  	switch d.state {
   475  	case decisionStateCanceledAfterInitiated:
   476  		d.moveState(decisionStateCancellationDecisionSent, eventDecisionSent)
   477  	default:
   478  		d.decisionStateMachineBase.handleDecisionSent()
   479  	}
   480  }
   481  
   482  func (d *timerDecisionStateMachine) handleCancelFailedEvent() {
   483  	switch d.state {
   484  	case decisionStateCancellationDecisionSent:
   485  		d.moveState(decisionStateInitiated, eventCancelFailed)
   486  	default:
   487  		d.decisionStateMachineBase.handleCancelFailedEvent()
   488  	}
   489  }
   490  
   491  func (d *timerDecisionStateMachine) getDecision() *s.Decision {
   492  	switch d.state {
   493  	case decisionStateCreated:
   494  		decision := createNewDecision(s.DecisionTypeStartTimer)
   495  		decision.StartTimerDecisionAttributes = d.attributes
   496  		return decision
   497  	case decisionStateCanceledAfterInitiated:
   498  		decision := createNewDecision(s.DecisionTypeCancelTimer)
   499  		decision.CancelTimerDecisionAttributes = &s.CancelTimerDecisionAttributes{
   500  			TimerId: d.attributes.TimerId,
   501  		}
   502  		return decision
   503  	default:
   504  		return nil
   505  	}
   506  }
   507  
   508  func (d *childWorkflowDecisionStateMachine) getDecision() *s.Decision {
   509  	switch d.state {
   510  	case decisionStateCreated:
   511  		decision := createNewDecision(s.DecisionTypeStartChildWorkflowExecution)
   512  		decision.StartChildWorkflowExecutionDecisionAttributes = d.attributes
   513  		return decision
   514  	case decisionStateCanceledAfterStarted:
   515  		decision := createNewDecision(s.DecisionTypeRequestCancelExternalWorkflowExecution)
   516  		decision.RequestCancelExternalWorkflowExecutionDecisionAttributes = &s.RequestCancelExternalWorkflowExecutionDecisionAttributes{
   517  			Domain:            d.attributes.Domain,
   518  			WorkflowId:        d.attributes.WorkflowId,
   519  			ChildWorkflowOnly: common.BoolPtr(true),
   520  		}
   521  		return decision
   522  	default:
   523  		return nil
   524  	}
   525  }
   526  
   527  func (d *childWorkflowDecisionStateMachine) handleDecisionSent() {
   528  	switch d.state {
   529  	case decisionStateCanceledAfterStarted:
   530  		d.moveState(decisionStateCancellationDecisionSent, eventDecisionSent)
   531  	default:
   532  		d.decisionStateMachineBase.handleDecisionSent()
   533  	}
   534  }
   535  
   536  func (d *childWorkflowDecisionStateMachine) handleStartedEvent() {
   537  	switch d.state {
   538  	case decisionStateInitiated:
   539  		d.moveState(decisionStateStarted, eventStarted)
   540  	case decisionStateCanceledAfterInitiated:
   541  		d.moveState(decisionStateCanceledAfterStarted, eventStarted)
   542  	default:
   543  		d.decisionStateMachineBase.handleStartedEvent()
   544  	}
   545  }
   546  
   547  func (d *childWorkflowDecisionStateMachine) handleCancelFailedEvent() {
   548  	switch d.state {
   549  	case decisionStateCancellationDecisionSent:
   550  		d.moveState(decisionStateStarted, eventCancelFailed)
   551  	default:
   552  		d.decisionStateMachineBase.handleCancelFailedEvent()
   553  	}
   554  }
   555  
   556  func (d *childWorkflowDecisionStateMachine) cancel() {
   557  	switch d.state {
   558  	case decisionStateStarted:
   559  		d.moveState(decisionStateCanceledAfterStarted, eventCancel)
   560  	default:
   561  		d.decisionStateMachineBase.cancel()
   562  	}
   563  }
   564  
   565  func (d *childWorkflowDecisionStateMachine) handleCanceledEvent() {
   566  	switch d.state {
   567  	case decisionStateStarted:
   568  		d.moveState(decisionStateCompleted, eventCanceled)
   569  	default:
   570  		d.decisionStateMachineBase.handleCanceledEvent()
   571  	}
   572  }
   573  
   574  func (d *childWorkflowDecisionStateMachine) handleCompletionEvent() {
   575  	switch d.state {
   576  	case decisionStateStarted, decisionStateCanceledAfterStarted:
   577  		d.moveState(decisionStateCompleted, eventCompletion)
   578  	default:
   579  		d.decisionStateMachineBase.handleCompletionEvent()
   580  	}
   581  }
   582  
   583  func (d *naiveDecisionStateMachine) getDecision() *s.Decision {
   584  	switch d.state {
   585  	case decisionStateCreated:
   586  		return d.decision
   587  	default:
   588  		return nil
   589  	}
   590  }
   591  
   592  func (d *naiveDecisionStateMachine) cancel() {
   593  	panic("unsupported operation")
   594  }
   595  
   596  func (d *naiveDecisionStateMachine) handleCompletionEvent() {
   597  	panic("unsupported operation")
   598  }
   599  
   600  func (d *naiveDecisionStateMachine) handleInitiatedEvent() {
   601  	panic("unsupported operation")
   602  }
   603  
   604  func (d *naiveDecisionStateMachine) handleInitiationFailedEvent() {
   605  	panic("unsupported operation")
   606  }
   607  
   608  func (d *naiveDecisionStateMachine) handleStartedEvent() {
   609  	panic("unsupported operation")
   610  }
   611  
   612  func (d *naiveDecisionStateMachine) handleCanceledEvent() {
   613  	panic("unsupported operation")
   614  }
   615  
   616  func (d *naiveDecisionStateMachine) handleCancelFailedEvent() {
   617  	panic("unsupported operation")
   618  }
   619  
   620  func (d *naiveDecisionStateMachine) handleCancelInitiatedEvent() {
   621  	panic("unsupported operation")
   622  }
   623  
   624  func (d *cancelExternalWorkflowDecisionStateMachine) handleInitiatedEvent() {
   625  	switch d.state {
   626  	case decisionStateDecisionSent:
   627  		d.moveState(decisionStateInitiated, eventInitiated)
   628  	default:
   629  		d.failStateTransition(eventInitiated)
   630  	}
   631  }
   632  
   633  func (d *cancelExternalWorkflowDecisionStateMachine) handleCompletionEvent() {
   634  	switch d.state {
   635  	case decisionStateInitiated:
   636  		d.moveState(decisionStateCompleted, eventCompletion)
   637  	default:
   638  		d.failStateTransition(eventCompletion)
   639  	}
   640  }
   641  
   642  func (d *signalExternalWorkflowDecisionStateMachine) handleInitiatedEvent() {
   643  	switch d.state {
   644  	case decisionStateDecisionSent:
   645  		d.moveState(decisionStateInitiated, eventInitiated)
   646  	default:
   647  		d.failStateTransition(eventInitiated)
   648  	}
   649  }
   650  
   651  func (d *signalExternalWorkflowDecisionStateMachine) handleCompletionEvent() {
   652  	switch d.state {
   653  	case decisionStateInitiated:
   654  		d.moveState(decisionStateCompleted, eventCompletion)
   655  	default:
   656  		d.failStateTransition(eventCompletion)
   657  	}
   658  }
   659  
   660  func (d *markerDecisionStateMachine) handleDecisionSent() {
   661  	// Marker decision state machine is considered as completed once decision is sent.
   662  	// For SideEffect/Version markers, when the history event is applied, there is no marker decision state machine yet
   663  	// because we preload those marker events.
   664  	// For local activity, when we apply the history event, we use it to create the marker state machine, there is no
   665  	// other event to drive it to completed state.
   666  	switch d.state {
   667  	case decisionStateCreated:
   668  		d.moveState(decisionStateCompleted, eventDecisionSent)
   669  	}
   670  }
   671  
   672  func (d *upsertSearchAttributesDecisionStateMachine) handleDecisionSent() {
   673  	// This decision is considered as completed once decision is sent.
   674  	switch d.state {
   675  	case decisionStateCreated:
   676  		d.moveState(decisionStateCompleted, eventDecisionSent)
   677  	}
   678  }
   679  
   680  func newDecisionsHelper() *decisionsHelper {
   681  	return &decisionsHelper{
   682  		orderedDecisions: list.New(),
   683  		decisions:        make(map[decisionID]*list.Element),
   684  
   685  		scheduledEventIDToActivityID:     make(map[int64]string),
   686  		scheduledEventIDToCancellationID: make(map[int64]string),
   687  		scheduledEventIDToSignalID:       make(map[int64]string),
   688  	}
   689  }
   690  
   691  func (h *decisionsHelper) getDecision(id decisionID) decisionStateMachine {
   692  	decision, ok := h.decisions[id]
   693  	if !ok {
   694  		panicMsg := fmt.Sprintf("unknown decision %v, possible causes are nondeterministic workflow definition code"+
   695  			" or incompatible change in the workflow definition", id)
   696  		panicIllegalState(panicMsg)
   697  	}
   698  	// Move the last update decision state machine to the back of the list.
   699  	// Otherwise decisions (like timer cancellations) can end up out of order.
   700  	h.orderedDecisions.MoveToBack(decision)
   701  	return decision.Value.(decisionStateMachine)
   702  }
   703  
   704  func (h *decisionsHelper) addDecision(decision decisionStateMachine) {
   705  	if _, ok := h.decisions[decision.getID()]; ok {
   706  		panicMsg := fmt.Sprintf("adding duplicate decision %v", decision)
   707  		panicIllegalState(panicMsg)
   708  	}
   709  	element := h.orderedDecisions.PushBack(decision)
   710  	h.decisions[decision.getID()] = element
   711  }
   712  
   713  func (h *decisionsHelper) scheduleActivityTask(attributes *s.ScheduleActivityTaskDecisionAttributes) decisionStateMachine {
   714  	decision := h.newActivityDecisionStateMachine(attributes)
   715  	h.addDecision(decision)
   716  	return decision
   717  }
   718  
   719  func (h *decisionsHelper) requestCancelActivityTask(activityID string) decisionStateMachine {
   720  	id := makeDecisionID(decisionTypeActivity, activityID)
   721  	decision := h.getDecision(id)
   722  	decision.cancel()
   723  	return decision
   724  }
   725  
   726  func (h *decisionsHelper) handleActivityTaskClosed(activityID string) decisionStateMachine {
   727  	decision := h.getDecision(makeDecisionID(decisionTypeActivity, activityID))
   728  	decision.handleCompletionEvent()
   729  	return decision
   730  }
   731  
   732  func (h *decisionsHelper) handleActivityTaskScheduled(scheduledEventID int64, activityID string) {
   733  	h.scheduledEventIDToActivityID[scheduledEventID] = activityID
   734  	decision := h.getDecision(makeDecisionID(decisionTypeActivity, activityID))
   735  	decision.handleInitiatedEvent()
   736  }
   737  
   738  func (h *decisionsHelper) handleActivityTaskCancelRequested(activityID string) {
   739  	decision := h.getDecision(makeDecisionID(decisionTypeActivity, activityID))
   740  	decision.handleCancelInitiatedEvent()
   741  }
   742  
   743  func (h *decisionsHelper) handleActivityTaskCanceled(activityID string) decisionStateMachine {
   744  	decision := h.getDecision(makeDecisionID(decisionTypeActivity, activityID))
   745  	decision.handleCanceledEvent()
   746  	return decision
   747  }
   748  
   749  func (h *decisionsHelper) handleRequestCancelActivityTaskFailed(activityID string) {
   750  	decision := h.getDecision(makeDecisionID(decisionTypeActivity, activityID))
   751  	decision.handleCancelFailedEvent()
   752  }
   753  
   754  func (h *decisionsHelper) getActivityID(event *s.HistoryEvent) string {
   755  	var scheduledEventID int64 = -1
   756  	switch event.GetEventType() {
   757  	case s.EventTypeActivityTaskCanceled:
   758  		scheduledEventID = event.ActivityTaskCanceledEventAttributes.GetScheduledEventId()
   759  	case s.EventTypeActivityTaskCompleted:
   760  		scheduledEventID = event.ActivityTaskCompletedEventAttributes.GetScheduledEventId()
   761  	case s.EventTypeActivityTaskFailed:
   762  		scheduledEventID = event.ActivityTaskFailedEventAttributes.GetScheduledEventId()
   763  	case s.EventTypeActivityTaskTimedOut:
   764  		scheduledEventID = event.ActivityTaskTimedOutEventAttributes.GetScheduledEventId()
   765  	default:
   766  		panicIllegalState(fmt.Sprintf("unexpected event type %v", event.GetEventType()))
   767  	}
   768  
   769  	activityID, ok := h.scheduledEventIDToActivityID[scheduledEventID]
   770  	if !ok {
   771  		panicIllegalState(fmt.Sprintf("unable to find activity ID for the event %v", util.HistoryEventToString(event)))
   772  	}
   773  	return activityID
   774  }
   775  
   776  func (h *decisionsHelper) recordVersionMarker(changeID string, version Version, dataConverter DataConverter) decisionStateMachine {
   777  	markerID := fmt.Sprintf("%v_%v", versionMarkerName, changeID)
   778  	details, err := encodeArgs(dataConverter, []interface{}{changeID, version})
   779  	if err != nil {
   780  		panic(err)
   781  	}
   782  
   783  	recordMarker := &s.RecordMarkerDecisionAttributes{
   784  		MarkerName: common.StringPtr(versionMarkerName),
   785  		Details:    details, // Keep
   786  	}
   787  
   788  	decision := h.newMarkerDecisionStateMachine(markerID, recordMarker)
   789  	h.addDecision(decision)
   790  	return decision
   791  }
   792  
   793  func (h *decisionsHelper) recordSideEffectMarker(sideEffectID int32, data []byte) decisionStateMachine {
   794  	markerID := fmt.Sprintf("%v_%v", sideEffectMarkerName, sideEffectID)
   795  	attributes := &s.RecordMarkerDecisionAttributes{
   796  		MarkerName: common.StringPtr(sideEffectMarkerName),
   797  		Details:    data,
   798  	}
   799  	decision := h.newMarkerDecisionStateMachine(markerID, attributes)
   800  	h.addDecision(decision)
   801  	return decision
   802  }
   803  
   804  func (h *decisionsHelper) recordLocalActivityMarker(activityID string, result []byte) decisionStateMachine {
   805  	markerID := fmt.Sprintf("%v_%v", localActivityMarkerName, activityID)
   806  	attributes := &s.RecordMarkerDecisionAttributes{
   807  		MarkerName: common.StringPtr(localActivityMarkerName),
   808  		Details:    result,
   809  	}
   810  	decision := h.newMarkerDecisionStateMachine(markerID, attributes)
   811  	h.addDecision(decision)
   812  	return decision
   813  }
   814  
   815  func (h *decisionsHelper) recordMutableSideEffectMarker(mutableSideEffectID string, data []byte) decisionStateMachine {
   816  	markerID := fmt.Sprintf("%v_%v", mutableSideEffectMarkerName, mutableSideEffectID)
   817  	attributes := &s.RecordMarkerDecisionAttributes{
   818  		MarkerName: common.StringPtr(mutableSideEffectMarkerName),
   819  		Details:    data,
   820  	}
   821  	decision := h.newMarkerDecisionStateMachine(markerID, attributes)
   822  	h.addDecision(decision)
   823  	return decision
   824  }
   825  
   826  func (h *decisionsHelper) startChildWorkflowExecution(attributes *s.StartChildWorkflowExecutionDecisionAttributes) decisionStateMachine {
   827  	decision := h.newChildWorkflowDecisionStateMachine(attributes)
   828  	h.addDecision(decision)
   829  	return decision
   830  }
   831  
   832  func (h *decisionsHelper) handleStartChildWorkflowExecutionInitiated(workflowID string) {
   833  	decision := h.getDecision(makeDecisionID(decisionTypeChildWorkflow, workflowID))
   834  	decision.handleInitiatedEvent()
   835  }
   836  
   837  func (h *decisionsHelper) handleStartChildWorkflowExecutionFailed(workflowID string) decisionStateMachine {
   838  	decision := h.getDecision(makeDecisionID(decisionTypeChildWorkflow, workflowID))
   839  	decision.handleInitiationFailedEvent()
   840  	return decision
   841  }
   842  
   843  func (h *decisionsHelper) requestCancelExternalWorkflowExecution(domain, workflowID, runID string, cancellationID string, childWorkflowOnly bool) decisionStateMachine {
   844  	if childWorkflowOnly {
   845  		// For cancellation of child workflow only, we do not use cancellation ID
   846  		// since the child workflow cancellation go through the existing child workflow
   847  		// state machine, and we use workflow ID as identifier
   848  		// we also do not use run ID, since child workflow can do continue-as-new
   849  		// which will have different run ID
   850  		// there will be server side validation that target workflow is child workflow
   851  
   852  		// sanity check that cancellation ID is not set
   853  		if len(cancellationID) != 0 {
   854  			panic("cancellation on child workflow should not use cancellation ID")
   855  		}
   856  		// sanity check that run ID is not set
   857  		if len(runID) != 0 {
   858  			panic("cancellation on child workflow should not use run ID")
   859  		}
   860  		// targeting child workflow
   861  		decision := h.getDecision(makeDecisionID(decisionTypeChildWorkflow, workflowID))
   862  		decision.cancel()
   863  		return decision
   864  	}
   865  
   866  	// For cancellation of external workflow, we have to use cancellation ID
   867  	// to identify different cancellation request (decision) / response (history event)
   868  	// client can also use this code path to cancel its own child workflow, however, there will
   869  	// be no server side validation that target workflow is the child
   870  
   871  	// sanity check that cancellation ID is set
   872  	if len(cancellationID) == 0 {
   873  		panic("cancellation on external workflow should use cancellation ID")
   874  	}
   875  	attributes := &s.RequestCancelExternalWorkflowExecutionDecisionAttributes{
   876  		Domain:            common.StringPtr(domain),
   877  		WorkflowId:        common.StringPtr(workflowID),
   878  		RunId:             common.StringPtr(runID),
   879  		Control:           []byte(cancellationID),
   880  		ChildWorkflowOnly: common.BoolPtr(false),
   881  	}
   882  	decision := h.newCancelExternalWorkflowStateMachine(attributes, cancellationID)
   883  	h.addDecision(decision)
   884  
   885  	return decision
   886  }
   887  
   888  func (h *decisionsHelper) handleRequestCancelExternalWorkflowExecutionInitiated(initiatedeventID int64, workflowID, cancellationID string) {
   889  	if h.isCancelExternalWorkflowEventForChildWorkflow(cancellationID) {
   890  		// this is cancellation for child workflow only
   891  		decision := h.getDecision(makeDecisionID(decisionTypeChildWorkflow, workflowID))
   892  		decision.handleCancelInitiatedEvent()
   893  	} else {
   894  		// this is cancellation for external workflow
   895  		h.scheduledEventIDToCancellationID[initiatedeventID] = cancellationID
   896  		decision := h.getDecision(makeDecisionID(decisionTypeCancellation, cancellationID))
   897  		decision.handleInitiatedEvent()
   898  	}
   899  }
   900  
   901  func (h *decisionsHelper) handleExternalWorkflowExecutionCancelRequested(initiatedeventID int64, workflowID string) (bool, decisionStateMachine) {
   902  	var decision decisionStateMachine
   903  	cancellationID, isExternal := h.scheduledEventIDToCancellationID[initiatedeventID]
   904  	if !isExternal {
   905  		decision = h.getDecision(makeDecisionID(decisionTypeChildWorkflow, workflowID))
   906  		// no state change for child workflow, it is still in CancellationDecisionSent
   907  	} else {
   908  		// this is cancellation for external workflow
   909  		decision = h.getDecision(makeDecisionID(decisionTypeCancellation, cancellationID))
   910  		decision.handleCompletionEvent()
   911  	}
   912  	return isExternal, decision
   913  }
   914  
   915  func (h *decisionsHelper) handleRequestCancelExternalWorkflowExecutionFailed(initiatedeventID int64, workflowID string) (bool, decisionStateMachine) {
   916  	var decision decisionStateMachine
   917  	cancellationID, isExternal := h.scheduledEventIDToCancellationID[initiatedeventID]
   918  	if !isExternal {
   919  		// this is cancellation for child workflow only
   920  		decision = h.getDecision(makeDecisionID(decisionTypeChildWorkflow, workflowID))
   921  		decision.handleCancelFailedEvent()
   922  	} else {
   923  		// this is cancellation for external workflow
   924  		decision = h.getDecision(makeDecisionID(decisionTypeCancellation, cancellationID))
   925  		decision.handleCompletionEvent()
   926  	}
   927  	return isExternal, decision
   928  }
   929  
   930  func (h *decisionsHelper) signalExternalWorkflowExecution(domain, workflowID, runID, signalName string, input []byte, signalID string, childWorkflowOnly bool) decisionStateMachine {
   931  	attributes := &s.SignalExternalWorkflowExecutionDecisionAttributes{
   932  		Domain: common.StringPtr(domain),
   933  		Execution: &s.WorkflowExecution{
   934  			WorkflowId: common.StringPtr(workflowID),
   935  			RunId:      common.StringPtr(runID),
   936  		},
   937  		SignalName:        common.StringPtr(signalName),
   938  		Input:             input,
   939  		Control:           []byte(signalID),
   940  		ChildWorkflowOnly: common.BoolPtr(childWorkflowOnly),
   941  	}
   942  	decision := h.newSignalExternalWorkflowStateMachine(attributes, signalID)
   943  	h.addDecision(decision)
   944  	return decision
   945  }
   946  
   947  func (h *decisionsHelper) upsertSearchAttributes(upsertID string, searchAttr *s.SearchAttributes) decisionStateMachine {
   948  	attributes := &s.UpsertWorkflowSearchAttributesDecisionAttributes{
   949  		SearchAttributes: searchAttr,
   950  	}
   951  	decision := h.newUpsertSearchAttributesStateMachine(attributes, upsertID)
   952  	h.addDecision(decision)
   953  	return decision
   954  }
   955  
   956  func (h *decisionsHelper) handleSignalExternalWorkflowExecutionInitiated(initiatedEventID int64, signalID string) {
   957  	h.scheduledEventIDToSignalID[initiatedEventID] = signalID
   958  	decision := h.getDecision(makeDecisionID(decisionTypeSignal, signalID))
   959  	decision.handleInitiatedEvent()
   960  }
   961  
   962  func (h *decisionsHelper) handleSignalExternalWorkflowExecutionCompleted(initiatedEventID int64) decisionStateMachine {
   963  	decision := h.getDecision(makeDecisionID(decisionTypeSignal, h.getSignalID(initiatedEventID)))
   964  	decision.handleCompletionEvent()
   965  	return decision
   966  }
   967  
   968  func (h *decisionsHelper) handleSignalExternalWorkflowExecutionFailed(initiatedEventID int64) decisionStateMachine {
   969  	decision := h.getDecision(makeDecisionID(decisionTypeSignal, h.getSignalID(initiatedEventID)))
   970  	decision.handleCompletionEvent()
   971  	return decision
   972  }
   973  
   974  func (h *decisionsHelper) getSignalID(initiatedEventID int64) string {
   975  	signalID, ok := h.scheduledEventIDToSignalID[initiatedEventID]
   976  	if !ok {
   977  		panic(fmt.Sprintf("unable to find signal ID: %v", initiatedEventID))
   978  	}
   979  	return signalID
   980  }
   981  
   982  func (h *decisionsHelper) startTimer(attributes *s.StartTimerDecisionAttributes) decisionStateMachine {
   983  	decision := h.newTimerDecisionStateMachine(attributes)
   984  	h.addDecision(decision)
   985  	return decision
   986  }
   987  
   988  func (h *decisionsHelper) cancelTimer(timerID string) decisionStateMachine {
   989  	decision := h.getDecision(makeDecisionID(decisionTypeTimer, timerID))
   990  	decision.cancel()
   991  	return decision
   992  }
   993  
   994  func (h *decisionsHelper) handleTimerClosed(timerID string) decisionStateMachine {
   995  	decision := h.getDecision(makeDecisionID(decisionTypeTimer, timerID))
   996  	decision.handleCompletionEvent()
   997  	return decision
   998  }
   999  
  1000  func (h *decisionsHelper) handleTimerStarted(timerID string) {
  1001  	decision := h.getDecision(makeDecisionID(decisionTypeTimer, timerID))
  1002  	decision.handleInitiatedEvent()
  1003  }
  1004  
  1005  func (h *decisionsHelper) handleTimerCanceled(timerID string) {
  1006  	decision := h.getDecision(makeDecisionID(decisionTypeTimer, timerID))
  1007  	decision.handleCanceledEvent()
  1008  }
  1009  
  1010  func (h *decisionsHelper) handleCancelTimerFailed(timerID string) {
  1011  	decision := h.getDecision(makeDecisionID(decisionTypeTimer, timerID))
  1012  	decision.handleCancelFailedEvent()
  1013  }
  1014  
  1015  func (h *decisionsHelper) handleChildWorkflowExecutionStarted(workflowID string) decisionStateMachine {
  1016  	decision := h.getDecision(makeDecisionID(decisionTypeChildWorkflow, workflowID))
  1017  	decision.handleStartedEvent()
  1018  	return decision
  1019  }
  1020  
  1021  func (h *decisionsHelper) handleChildWorkflowExecutionClosed(workflowID string) decisionStateMachine {
  1022  	decision := h.getDecision(makeDecisionID(decisionTypeChildWorkflow, workflowID))
  1023  	decision.handleCompletionEvent()
  1024  	return decision
  1025  }
  1026  
  1027  func (h *decisionsHelper) handleChildWorkflowExecutionCanceled(workflowID string) decisionStateMachine {
  1028  	decision := h.getDecision(makeDecisionID(decisionTypeChildWorkflow, workflowID))
  1029  	decision.handleCanceledEvent()
  1030  	return decision
  1031  }
  1032  
  1033  func (h *decisionsHelper) getDecisions(markAsSent bool) []*s.Decision {
  1034  	var result []*s.Decision
  1035  	for curr := h.orderedDecisions.Front(); curr != nil; {
  1036  		next := curr.Next() // get next item here as we might need to remove curr in the loop
  1037  		d := curr.Value.(decisionStateMachine)
  1038  		decision := d.getDecision()
  1039  		if decision != nil {
  1040  			result = append(result, decision)
  1041  		}
  1042  
  1043  		if markAsSent {
  1044  			d.handleDecisionSent()
  1045  		}
  1046  
  1047  		// remove completed decision state machines
  1048  		if d.getState() == decisionStateCompleted {
  1049  			h.orderedDecisions.Remove(curr)
  1050  			delete(h.decisions, d.getID())
  1051  		}
  1052  
  1053  		curr = next
  1054  	}
  1055  
  1056  	return result
  1057  }
  1058  
  1059  func (h *decisionsHelper) isCancelExternalWorkflowEventForChildWorkflow(cancellationID string) bool {
  1060  	// the cancellationID, i.e. Control in RequestCancelExternalWorkflowExecutionInitiatedEventAttributes
  1061  	// will be empty if the event is for child workflow.
  1062  	// for cancellation external workflow, Control in RequestCancelExternalWorkflowExecutionInitiatedEventAttributes
  1063  	// will have a client generated sequence ID
  1064  	return len(cancellationID) == 0
  1065  }