# Async Drain Signals?

**URL:** <https://community.temporal.io/t/async-drain-signals/7300>\
**Category:** Community Support\
**Tags:** go-sdk\
**Created:** [February 16, 2023, 9:54pm UTC](https://community.temporal.io/t/async-drain-signals/7300 "2023-02-16T21:54:18Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![AlbertL](https://sea2.discourse-cdn.com/flex016/user_avatar/community.temporal.io/albertl/32/2825_2.png) [@AlbertL](https://community.temporal.io/u/AlbertL)\
**Post date:** [February 16, 2023, 9:54pm UTC](https://community.temporal.io/t/async-drain-signals/7300/1 "2023-02-16T21:54:18Z")

</div>

Hi,

I’m a bit confused as to what the documentation means by `make sure to do an asynchronous drain on the Signal channel`. Is the following an async drain? If not, what should I be doing?

```auto
func SimpleWorkflow(ctx workflow.Context) error {
	workflow.Go(ctx, func(ctx workflow.Context) {
		var signal string
		signalChan := workflow.GetSignalChannel(ctx, "simple")
		selector := workflow.NewNamedSelector(ctx, "simple selector")
		selector.AddReceive(signalChan, func(channel workflow.ReceiveChannel, more bool) {
			channel.Receive(ctx, &signal)
		})
		for {
			selector.Select(ctx)
			workflow.GetLogger(ctx).Info("received signal", signal)
		}
	})

	for i := 0; i < 10; i++ {
		if err := workflow.Sleep(ctx, 30*time.Second); err != nil {
			return err
		}
	}
	return workflow.NewContinueAsNewError(ctx, SimpleWorkflow)
}

```

---

<div class="post-metadata">

**Author:** ![tihomir](https://sea2.discourse-cdn.com/flex016/user_avatar/community.temporal.io/tihomir/32/6580_2.png) [@tihomir](https://community.temporal.io/u/tihomir)\
**Post date:** [February 16, 2023, 9:56pm UTC](https://community.temporal.io/t/async-drain-signals/7300/2 "2023-02-16T21:56:09Z")

</div>

Take a look at post [here](https://community.temporal.io/t/go-sdk-sequential-by-id-otherwise-in-parallel/1486/5) for sample code impl (use of ReceiveAsync).

---

<div class="post-metadata">

**Author:** ![AlbertL](https://sea2.discourse-cdn.com/flex016/user_avatar/community.temporal.io/albertl/32/2825_2.png) [@AlbertL](https://community.temporal.io/u/AlbertL)\
**Post date:** [February 16, 2023, 10:13pm UTC](https://community.temporal.io/t/async-drain-signals/7300/3 "2023-02-16T22:13:05Z")

</div>

Oh… I see. So if I had several of signal receivers in various `workflow.Go` functions, then I would need to stop them and then do a `ReceiveAsync` on each receiver not in a `workflow.Go` function before exiting?

---

<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 16, 2023, 11:07pm UTC](https://community.temporal.io/t/async-drain-signals/7300/4 "2023-02-16T23:07:25Z")

</div>

There is no even need to stop them as they are guaranteed not to run while the main workflow goroutine is executing.

---

<div class="post-metadata">

**Author:** ![AlbertL](https://sea2.discourse-cdn.com/flex016/user_avatar/community.temporal.io/albertl/32/2825_2.png) [@AlbertL](https://community.temporal.io/u/AlbertL)\
**Post date:** [February 17, 2023, 2:05am UTC](https://community.temporal.io/t/async-drain-signals/7300/5 "2023-02-17T02:05:33Z")

</div>

Interesting. I must have missed that in the documentation.

Sorry for the tangent… let’s say that there are two `workflow.Go` routines, can they run in parallel or does Temporal limit the workflow to only one active task at one time?

---

<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 17, 2023, 6:07pm UTC](https://community.temporal.io/t/async-drain-signals/7300/6 "2023-02-17T18:07:35Z")

</div>

Workflow code must be deterministic. The only way to run code that contains multiple goroutines is to use cooperative multi-threading. This means that only one goroutine per workflow runs at a time. When it blocks on some Temporal API like Sleep or Fugure.Get the control is passed back to Temporal SDK and the next goroutine is unblocked.

> does Temporal limit the workflow to only one active task at one time?

I don’t know what you mean by task in this context. If you have two goroutines scheduling two activities then both activities will run in parallel.

---

<div class="post-metadata">

**Author:** ![AlbertL](https://sea2.discourse-cdn.com/flex016/user_avatar/community.temporal.io/albertl/32/2825_2.png) [@AlbertL](https://community.temporal.io/u/AlbertL)\
**Post date:** [February 17, 2023, 6:32pm UTC](https://community.temporal.io/t/async-drain-signals/7300/7 "2023-02-17T18:32:29Z")

</div>

Thank you! This was super enlightening.

---

<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 19, 2023, 10:15pm UTC](https://community.temporal.io/t/async-drain-signals/7300/8 "2023-02-19T22:15:28Z")

</div>

> [@maxim](#):
>
> There is no even need to stop them as they are guaranteed not to run while the main workflow goroutine is executing.

I missed one edge case. If there is a goroutine blocked on `Channel.Receive`. Then a new message can be allocated to that call (even if its goroutine never wakes up) and never delivered to `Channel.ReceiveAsync` from a different goroutine. So to ensure no message loss the code needs to ensure that no other goroutine is still consuming from the same channel before draining it.

This looks like a design bug in the way the Channel is implemented. If filed an [issue](https://github.com/temporalio/sdk-go/issues/1048) to get this looked at.
