@@ -1715,75 +1715,99 @@ func (w *workflowClientInterceptor) executeWorkflowWithOperation(
1715
1715
withStartOp ,
1716
1716
},
1717
1717
}
1718
- multiResp , err := w .client .workflowService .ExecuteMultiOperation (ctx , & multiRequest )
1719
1718
1720
- var multiErr * serviceerror.MultiOperationExecution
1721
- if errors .As (err , & multiErr ) {
1722
- if len (multiErr .OperationErrors ()) != len (multiRequest .Operations ) {
1723
- return nil , fmt .Errorf ("%w: %v instead of %v operation errors" ,
1724
- errInvalidServerResponse , len (multiErr .OperationErrors ()), len (multiRequest .Operations ))
1719
+ var startResp * workflowservice.StartWorkflowExecutionResponse
1720
+ var updateResp * workflowservice.UpdateWorkflowExecutionResponse
1721
+ for {
1722
+ multiResp , err := func () (* workflowservice.ExecuteMultiOperationResponse , error ) {
1723
+ grpcCtx , cancel := newGRPCContext (ctx , grpcTimeout (pollUpdateTimeout ), grpcLongPoll (true ), defaultGrpcRetryParameters (ctx ))
1724
+ defer cancel ()
1725
+
1726
+ multiResp , err := w .client .workflowService .ExecuteMultiOperation (grpcCtx , & multiRequest )
1727
+ if err != nil {
1728
+ if ctx .Err () != nil {
1729
+ return nil , NewWorkflowUpdateServiceTimeoutOrCanceledError (err )
1730
+ }
1731
+ if status := serviceerror .ToStatus (err ); status .Code () == codes .Canceled || status .Code () == codes .DeadlineExceeded {
1732
+ return nil , NewWorkflowUpdateServiceTimeoutOrCanceledError (err )
1733
+ }
1734
+ return nil , err
1735
+ }
1736
+
1737
+ return multiResp , err
1738
+ }()
1739
+
1740
+ var multiErr * serviceerror.MultiOperationExecution
1741
+ if errors .As (err , & multiErr ) {
1742
+ if len (multiErr .OperationErrors ()) != len (multiRequest .Operations ) {
1743
+ return nil , fmt .Errorf ("%w: %v instead of %v operation errors" ,
1744
+ errInvalidServerResponse , len (multiErr .OperationErrors ()), len (multiRequest .Operations ))
1745
+ }
1746
+
1747
+ var abortedErr * serviceerror.MultiOperationAborted
1748
+ startErr := errors .New ("failed to start workflow" )
1749
+ for i , opReq := range multiRequest .Operations {
1750
+ // if an operation error is of type MultiOperationAborted, it means it was only aborted because
1751
+ // of another operation's error and is therefore not interesting or helpful
1752
+ opErr := multiErr .OperationErrors ()[i ]
1753
+
1754
+ switch t := opReq .Operation .(type ) {
1755
+ case * workflowservice.ExecuteMultiOperationRequest_Operation_StartWorkflow :
1756
+ if ! errors .As (opErr , & abortedErr ) {
1757
+ startErr = opErr
1758
+ }
1759
+ case * workflowservice.ExecuteMultiOperationRequest_Operation_UpdateWorkflow :
1760
+ if ! errors .As (opErr , & abortedErr ) {
1761
+ startErr = fmt .Errorf ("%w: %w" , errInvalidWorkflowOperation , opErr )
1762
+ }
1763
+ default :
1764
+ // this would only happen if a case statement for a newly added operation is missing above
1765
+ return nil , fmt .Errorf ("%w: %T" , errUnsupportedOperation , t )
1766
+ }
1767
+ }
1768
+ return nil , startErr
1769
+ } else if err != nil {
1770
+ return nil , err
1771
+ }
1772
+
1773
+ if len (multiResp .Responses ) != len (multiRequest .Operations ) {
1774
+ return nil , fmt .Errorf ("%w: %v instead of %v operation results" ,
1775
+ errInvalidServerResponse , len (multiResp .Responses ), len (multiRequest .Operations ))
1725
1776
}
1726
1777
1727
- var startErr error
1728
- var abortedErr * serviceerror.MultiOperationAborted
1729
1778
for i , opReq := range multiRequest .Operations {
1730
- // if an operation error is of type MultiOperationAborted, it means it was only aborted because
1731
- // of another operation's error and is therefore not interesting or helpful
1732
- opErr := multiErr .OperationErrors ()[i ]
1779
+ resp := multiResp .Responses [i ].Response
1733
1780
1734
1781
switch t := opReq .Operation .(type ) {
1735
1782
case * workflowservice.ExecuteMultiOperationRequest_Operation_StartWorkflow :
1736
- if ! errors .As (opErr , & abortedErr ) {
1737
- startErr = opErr
1783
+ if opResp , ok := resp .(* workflowservice.ExecuteMultiOperationResponse_Response_StartWorkflow ); ok {
1784
+ startResp = opResp .StartWorkflow
1785
+ } else {
1786
+ return nil , fmt .Errorf ("%w: StartWorkflow response has the wrong type %T" , errInvalidServerResponse , resp )
1738
1787
}
1739
1788
case * workflowservice.ExecuteMultiOperationRequest_Operation_UpdateWorkflow :
1740
- if ! errors .As (opErr , & abortedErr ) {
1741
- startErr = fmt .Errorf ("%w: %w" , errInvalidWorkflowOperation , opErr )
1789
+ if opResp , ok := resp .(* workflowservice.ExecuteMultiOperationResponse_Response_UpdateWorkflow ); ok {
1790
+ updateResp = opResp .UpdateWorkflow
1791
+ } else {
1792
+ return nil , fmt .Errorf ("%w: UpdateWorkflow response has the wrong type %T" , errInvalidServerResponse , resp )
1742
1793
}
1743
1794
default :
1744
1795
// this would only happen if a case statement for a newly added operation is missing above
1745
1796
return nil , fmt .Errorf ("%w: %T" , errUnsupportedOperation , t )
1746
1797
}
1747
1798
}
1748
- return nil , startErr
1749
- } else if err != nil {
1750
- return nil , err
1751
- }
1752
1799
1753
- if len ( multiResp . Responses ) != len ( multiRequest . Operations ) {
1754
- return nil , fmt . Errorf ( "%w: %v instead of %v operation results" ,
1755
- errInvalidServerResponse , len ( multiResp . Responses ), len ( multiRequest . Operations ))
1800
+ if w . updateIsDurable ( updateResp ) {
1801
+ break
1802
+ }
1756
1803
}
1757
1804
1758
- var startResp * workflowservice.StartWorkflowExecutionResponse
1759
- for i , opReq := range multiRequest .Operations {
1760
- resp := multiResp .Responses [i ].Response
1761
-
1762
- switch t := opReq .Operation .(type ) {
1763
- case * workflowservice.ExecuteMultiOperationRequest_Operation_StartWorkflow :
1764
- if opResp , ok := resp .(* workflowservice.ExecuteMultiOperationResponse_Response_StartWorkflow ); ok {
1765
- startResp = opResp .StartWorkflow
1766
- } else {
1767
- return nil , fmt .Errorf ("%w: StartWorkflow response has the wrong type %T" , errInvalidServerResponse , resp )
1768
- }
1769
- case * workflowservice.ExecuteMultiOperationRequest_Operation_UpdateWorkflow :
1770
- if opResp , ok := resp .(* workflowservice.ExecuteMultiOperationResponse_Response_UpdateWorkflow ); ok {
1771
- handle , err := w .updateHandleFromResponse (
1772
- ctx ,
1773
- enumspb .UPDATE_WORKFLOW_EXECUTION_LIFECYCLE_STAGE_UNSPECIFIED ,
1774
- opResp .UpdateWorkflow )
1775
- operation .(* UpdateWithStartWorkflowOperation ).set (handle , err )
1776
- if err != nil {
1777
- return nil , fmt .Errorf ("%w: %w" , errInvalidWorkflowOperation , err )
1778
- }
1779
- } else {
1780
- return nil , fmt .Errorf ("%w: UpdateWorkflow response has the wrong type %T" , errInvalidServerResponse , resp )
1781
- }
1782
- default :
1783
- // this would only happen if a case statement for a newly added operation is missing above
1784
- return nil , fmt .Errorf ("%w: %T" , errUnsupportedOperation , t )
1785
- }
1805
+ handle , err := w .updateHandleFromResponse (ctx , enumspb .UPDATE_WORKFLOW_EXECUTION_LIFECYCLE_STAGE_UNSPECIFIED , updateResp )
1806
+ operation .(* UpdateWithStartWorkflowOperation ).set (handle , err )
1807
+ if err != nil {
1808
+ return nil , fmt .Errorf ("%w: %w" , errInvalidWorkflowOperation , err )
1786
1809
}
1810
+
1787
1811
return startResp , nil
1788
1812
}
1789
1813
@@ -2028,11 +2052,7 @@ func (w *workflowClientInterceptor) UpdateWorkflow(
2028
2052
}
2029
2053
return nil , err
2030
2054
}
2031
- // Once the update is past admitted we know it is durable
2032
- // Note: old server version may return UNSPECIFIED if the update request
2033
- // did not reach the desired lifecycle stage.
2034
- if resp .GetStage () != enumspb .UPDATE_WORKFLOW_EXECUTION_LIFECYCLE_STAGE_ADMITTED &&
2035
- resp .GetStage () != enumspb .UPDATE_WORKFLOW_EXECUTION_LIFECYCLE_STAGE_UNSPECIFIED {
2055
+ if w .updateIsDurable (resp ) {
2036
2056
break
2037
2057
}
2038
2058
}
@@ -2042,6 +2062,14 @@ func (w *workflowClientInterceptor) UpdateWorkflow(
2042
2062
return w .updateHandleFromResponse (ctx , desiredLifecycleStage , resp )
2043
2063
}
2044
2064
2065
+ func (w * workflowClientInterceptor ) updateIsDurable (resp * workflowservice.UpdateWorkflowExecutionResponse ) bool {
2066
+ // Once the update is past admitted we know it is durable
2067
+ // Note: old server version may return UNSPECIFIED if the update request
2068
+ // did not reach the desired lifecycle stage.
2069
+ return resp .GetStage () != enumspb .UPDATE_WORKFLOW_EXECUTION_LIFECYCLE_STAGE_ADMITTED &&
2070
+ resp .GetStage () != enumspb .UPDATE_WORKFLOW_EXECUTION_LIFECYCLE_STAGE_UNSPECIFIED
2071
+ }
2072
+
2045
2073
func createUpdateWorkflowInput (
2046
2074
options UpdateWorkflowOptions ,
2047
2075
) (* ClientUpdateWorkflowInput , error ) {
0 commit comments