@@ -896,6 +896,14 @@ func (wc *workflowEnvironmentInterceptor) ExecuteChildWorkflow(ctx Context, chil
896
896
decodeFutureImpl : mainFuture .(* decodeFutureImpl ),
897
897
executionFuture : executionFuture .(* futureImpl ),
898
898
}
899
+
900
+ // Starting with a canceled context should immediately fail, no need to even try.
901
+ if ctx .Err () != nil {
902
+ mainSettable .SetError (ctx .Err ())
903
+ executionSettable .SetError (ctx .Err ())
904
+ return result
905
+ }
906
+
899
907
workflowOptionsFromCtx := getWorkflowEnvOptions (ctx )
900
908
dc := workflowOptionsFromCtx .dataConverter
901
909
env := getWorkflowEnvironment (ctx )
@@ -928,6 +936,7 @@ func (wc *workflowEnvironmentInterceptor) ExecuteChildWorkflow(ctx Context, chil
928
936
929
937
ctxDone , cancellable := ctx .Done ().(* channelImpl )
930
938
cancellationCallback := & receiveCallback {}
939
+ shouldCancelAsync := false
931
940
err = getWorkflowEnvironment (ctx ).ExecuteChildWorkflow (params , func (r []byte , e error ) {
932
941
mainSettable .Set (r , e )
933
942
if cancellable {
@@ -939,6 +948,11 @@ func (wc *workflowEnvironmentInterceptor) ExecuteChildWorkflow(ctx Context, chil
939
948
childWorkflowExecution = & r
940
949
}
941
950
executionSettable .Set (r , e )
951
+
952
+ // forward the delayed cancellation if necessary
953
+ if shouldCancelAsync && e == nil && ! mainFuture .IsReady () {
954
+ getWorkflowEnvironment (ctx ).RequestCancelChildWorkflow (* options .domain , childWorkflowExecution .ID )
955
+ }
942
956
})
943
957
944
958
if err != nil {
@@ -949,9 +963,19 @@ func (wc *workflowEnvironmentInterceptor) ExecuteChildWorkflow(ctx Context, chil
949
963
950
964
if cancellable {
951
965
cancellationCallback .fn = func (v interface {}, more bool ) bool {
952
- if ctx .Err () == ErrCanceled && childWorkflowExecution != nil && ! mainFuture .IsReady () {
953
- // child workflow started, and ctx cancelled
954
- getWorkflowEnvironment (ctx ).RequestCancelChildWorkflow (* options .domain , childWorkflowExecution .ID )
966
+ if ctx .Err () == ErrCanceled {
967
+ if childWorkflowExecution != nil && ! mainFuture .IsReady () {
968
+ // child workflow started, and ctx cancelled. forward cancel to the child.
969
+ getWorkflowEnvironment (ctx ).RequestCancelChildWorkflow (* options .domain , childWorkflowExecution .ID )
970
+ } else if childWorkflowExecution == nil {
971
+ // decision to start the child has been made, but it has not yet started.
972
+
973
+ // TODO: ideal, but not strictly necessary for correctness:
974
+ // if it's in the same decision, revoke that cancel synchronously.
975
+
976
+ // if the decision has already gone through: wait for it to be started, and then cancel it.
977
+ shouldCancelAsync = true
978
+ }
955
979
}
956
980
return false
957
981
}
0 commit comments