# Canceling Child Workflow Execution

**URL:** <https://community.temporal.io/t/canceling-child-workflow-execution/7373>\
**Category:** Community Support\
**Created:** [February 23, 2023, 4:17am UTC](https://community.temporal.io/t/canceling-child-workflow-execution/7373 "2023-02-23T04:17:39Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![Bryan](https://sea2.discourse-cdn.com/flex016/user_avatar/community.temporal.io/bryan/32/3245_2.png) [@Bryan](https://community.temporal.io/u/Bryan)\
**Post date:** [February 23, 2023, 4:17am UTC](https://community.temporal.io/t/canceling-child-workflow-execution/7373/1 "2023-02-23T04:17:39Z")

</div>

I’d like to ask about a parent canceling/terminating its child workflow execution.

There is parent workflow A executes a child workflow A with a timer. If the timer is triggered (timeout), the child wf is cancelled/terminated. Workflow A uses below versions:

- [go.temporal.io/api](http://go.temporal.io/api) v1.11.1-0.20220907050538-6de5285cf463
- [go.temporal.io/sdk](http://go.temporal.io/sdk) v1.17.0

Then, there is another parent workflow B, it executes a child workflow B with a timer. If the timer is triggered (timeout), the child wf should be cancelled/terminated. When I test it, the cwf is not cancelled although workflow B has the same code as workflow A. Workflow B uses below versions:

- [go.temporal.io/api](http://go.temporal.io/api) v1.13.0
- [go.temporal.io/sdk](http://go.temporal.io/sdk) v1.18.1

Below is the code snippet:

```auto
> childOptions := workflow.ChildWorkflowOptions{
> WorkflowID: childWorkflowId,
> RetryPolicy: retryPolicy,
> SearchAttributes: searchAttributes,
> TaskQueue: wf.TaskQueue,
> WorkflowIDReusePolicy: enums.WORKFLOW_ID_REUSE_POLICY_ALLOW_DUPLICATE,
> }
> ctx = workflow.WithChildOptions(ctx, childOptions)
> 
> childFuture := workflow.ExecuteChildWorkflow(ctx, utility.ChildWorkflowName, childWfReq)
> 
> loopCtx := workflow.WithActivityOptions(ctx, activityOptions)
> timerCtx, timerCancel := workflow.WithCancel(loopCtx)
> timer := workflow.NewTimer(timerCtx, dynamicConfig.Timer)
> selector := workflow.NewSelector(timerCtx)
> selector.AddFuture(timer, func(f workflow.Future) {
> err1 := f.Get(timerCtx, nil)
> if loopCtx.Err() != nil {
> logger.Error("Error occurred.", "error", loopCtx.Err())
> }
> }).AddFuture(childFuture, func(f workflow.Future) {
> err := childFuture.Get(ctx, &request)
> if err != nil {
> logger.Error("Error occurred getting child workflow result.", "error", err)
> }
> timerCancel()
> }).Select(loopCtx)
> }

```

1. Could the different behaviors caused by different sdk/api versions?

I tried to modify workflow B to manually cancel the child workflow:

- I added WaitForCancellation.

```auto
childOptions := workflow.ChildWorkflowOptions{
	...
	WaitForCancellation: true,
}

```

- I defined a cancel handler:

```auto
childCtx, cancelHandler := workflow.WithCancel(ctx)

```

- Then I called the handler when the timer is triggered:

```auto
cancelHandler()

```

However, the child workflow is still running. I also tried to use childCtx.Done() but it does not work.

---

<div class="post-metadata">

**Author:** ![maxim](https://sea2.discourse-cdn.com/flex016/user_avatar/community.temporal.io/maxim/32/8_2.png) [@maxim](https://community.temporal.io/u/maxim)\
**Post date:** [February 23, 2023, 5:46am UTC](https://community.temporal.io/t/canceling-child-workflow-execution/7373/2 "2023-02-23T05:46:36Z")

</div>

In the code snippet posted I don’t see any attempts to cancel the child.

---

<div class="post-metadata">

**Author:** ![Bryan](https://sea2.discourse-cdn.com/flex016/user_avatar/community.temporal.io/bryan/32/3245_2.png) [@Bryan](https://community.temporal.io/u/Bryan)\
**Post date:** [February 23, 2023, 7:45am UTC](https://community.temporal.io/t/canceling-child-workflow-execution/7373/3 "2023-02-23T07:45:02Z")

</div>

Yes, that is the code snippet of Workflow A. I don’t specify any cancelHandler, but when timer is triggered, the child WF is automatically terminated.

When the cwf is initiated, the parent close policy is PARENT\_CLOSE\_POLICY\_TERMINATE.

 ![image](https://us1.discourse-cdn.com/flex016/uploads/temporal/original/2X/d/d8b6330c97f00a0dc353fdf1f6bc12e97697d3e3.png)

However, I never specified parentClosePolicy in the childOptions as shown in the snnipet. So I assumed it would use the default policy as stated in docs.

 ![image](https://us1.discourse-cdn.com/flex016/uploads/temporal/original/2X/a/a90df83c9249c8f5182f7c3fa4cbbcbbb93efc04.png)

In Temporal WEB UI, the child WF is terminated. The reason in result section is ‘by parent close policy’.

 ![image](https://us1.discourse-cdn.com/flex016/uploads/temporal/original/2X/d/dce7c091189b7200ba2d392d77fa884d5056d0c6.png)

Using the same code, I applied it to workflow B. The parent close policy is PARENT\_CLOSE\_POLICY\_TERMINATE too.

 ![image](https://us1.discourse-cdn.com/flex016/uploads/temporal/original/2X/9/945757817f246a108a1207fcf692bb9f302e5ec3.png)

However, after the timer is triggered, the child WF is still running.

 ![image](https://us1.discourse-cdn.com/flex016/uploads/temporal/original/2X/4/462b6004c1aea1087ced0c2ebed6b9f62f1f045c.png)

---

<div class="post-metadata">

**Author:** ![maxim](https://sea2.discourse-cdn.com/flex016/user_avatar/community.temporal.io/maxim/32/8_2.png) [@maxim](https://community.temporal.io/u/maxim)\
**Post date:** [February 23, 2023, 4:00pm UTC](https://community.temporal.io/t/canceling-child-workflow-execution/7373/4 "2023-02-23T16:00:01Z")

</div>

I believe the documentation is incorrect, and PARENT\_CLOSE\_POLICY\_TERMINATE is the default.

In the case of Workflow A, what happened to the parent workflow?

In the case of Workflow B it behaves as designed as I believe the parent B doesn’t complete when timer fires.

Could you post histories for all 4 workflows?

---

<div class="post-metadata">

**Author:** ![Bryan](https://sea2.discourse-cdn.com/flex016/user_avatar/community.temporal.io/bryan/32/3245_2.png) [@Bryan](https://community.temporal.io/u/Bryan)\
**Post date:** [February 24, 2023, 4:50am UTC](https://community.temporal.io/t/canceling-child-workflow-execution/7373/5 "2023-02-24T04:50:07Z")

</div>

Parent workflow A continues to the next activities, but now it is Completed. Child workflow A is terminated.

I think I have found out why workflow A and B behave differently. Child workflow A is terminated because parent workflow A is already completed. Child workflow B is not terminated, because parent workflow B is still running.

Now the question is, how to cancel a running child workflow.

1. Using cancelHandler()  

2. Using ctx.Done()  

But both do not work because the child workflow is still running.

---

<div class="post-metadata">

**Author:** ![maxim](https://sea2.discourse-cdn.com/flex016/user_avatar/community.temporal.io/maxim/32/8_2.png) [@maxim](https://community.temporal.io/u/maxim)\
**Post date:** [February 24, 2023, 5:52pm UTC](https://community.temporal.io/t/canceling-child-workflow-execution/7373/6 "2023-02-24T17:52:16Z")

</div>

(1) is the correct way.

`childCtx.Done` returns the channel that is closed upon cancellation. But just returning that channel is NOOP.

Check both parent and child histories for the cancellation request.

---

<div class="post-metadata">

**Author:** ![Bryan](https://sea2.discourse-cdn.com/flex016/user_avatar/community.temporal.io/bryan/32/3245_2.png) [@Bryan](https://community.temporal.io/u/Bryan)\
**Post date:** [February 27, 2023, 5:59am UTC](https://community.temporal.io/t/canceling-child-workflow-execution/7373/7 "2023-02-27T05:59:41Z")

</div>

Hi Maxim,

(1) does send a cancellation request to child wf:

 ![image](https://us1.discourse-cdn.com/flex016/uploads/temporal/original/2X/6/6d4b469d0f86813fe3aa2a1f74cf3ed62b111965.png)  
 ![image](https://us1.discourse-cdn.com/flex016/uploads/temporal/original/2X/5/5ca6903ebf4affad8ac4dc186d5c22c1498c137d.png)

The child wf receives the request and the activity is cancelled.

 ![image](https://us1.discourse-cdn.com/flex016/uploads/temporal/original/2X/4/45c462ede7e908604a7131faff06aa4b9b86ae6a.png)  
 ![image](https://us1.discourse-cdn.com/flex016/uploads/temporal/original/2X/6/653ed1401bc819faa0ea8f603bcbdfd833decfa8.png)  
 ![image](https://us1.discourse-cdn.com/flex016/uploads/temporal/original/2X/2/267814affb1fdc2b15994934657c9eaabdcf5b74.png)

It has the same behavior as workflow.RequestCancelExternalWorkflow(ctx, cwfId, “”)

Yes (2) does not do anything to the child workflow. Does it only work for ExecuteActivity() and timer?

In conclusion, cancelling a child workflow works using (1). I just realize that cancelation and termination are 2 different activities. I read a topic that says to create a different activity to cancel the child workflow using Temporal client.

---

<div class="post-metadata">

**Author:** ![maxim](https://sea2.discourse-cdn.com/flex016/user_avatar/community.temporal.io/maxim/32/8_2.png) [@maxim](https://community.temporal.io/u/maxim)\
**Post date:** [February 27, 2023, 6:33pm UTC](https://community.temporal.io/t/canceling-child-workflow-execution/7373/8 "2023-02-27T18:33:21Z")

</div>

Look at the thread dump (stack trace tab in the UI) for the child workflow to see where it is blocked. In some cases, you have to handle context cancellation explicitly. For example, a selector has to handle the closure of context.Done channel.

---

<div class="post-metadata">

**Author:** ![Bryan](https://sea2.discourse-cdn.com/flex016/user_avatar/community.temporal.io/bryan/32/3245_2.png) [@Bryan](https://community.temporal.io/u/Bryan)\
**Post date:** [February 28, 2023, 2:54am UTC](https://community.temporal.io/t/canceling-child-workflow-execution/7373/9 "2023-02-28T02:54:08Z")

</div>

It is currently blocked due to waiting for a signal.

 ![image](https://us1.discourse-cdn.com/flex016/uploads/temporal/original/2X/7/7a35f21bde833d03d4293009185cf406d7bbb4f1.png)

The code below means the parent waits until the child context cancelation is done, right?

 ![image](https://us1.discourse-cdn.com/flex016/uploads/temporal/original/2X/0/0e0102dcf98946b64deb54e917b00a793cc63e19.png)

After the cancelation, can the child workflow continue to the next activities?

---

<div class="post-metadata">

**Author:** ![maxim](https://sea2.discourse-cdn.com/flex016/user_avatar/community.temporal.io/maxim/32/8_2.png) [@maxim](https://community.temporal.io/u/maxim)\
**Post date:** [February 28, 2023, 3:00am UTC](https://community.temporal.io/t/canceling-child-workflow-execution/7373/10 "2023-02-28T03:00:57Z")

</div>

So the child doesn’t handle context cancellation as `Channel.Receive` is not interrupted by it.

The code snippet can be used to handle the context cancellation.

---

<div class="post-metadata">

**Author:** ![Bryan](https://sea2.discourse-cdn.com/flex016/user_avatar/community.temporal.io/bryan/32/3245_2.png) [@Bryan](https://community.temporal.io/u/Bryan)\
**Post date:** [February 28, 2023, 8:49am UTC](https://community.temporal.io/t/canceling-child-workflow-execution/7373/11 "2023-02-28T08:49:38Z")

</div>

Yes, the child has not handled context cancelation.

I see, okay thank you for the help.
