Go Context for a layman

ANUPAM GOGOI
4 min readFeb 6, 2022

Introduction

The context is a critical part of the whole Go ecosystem. In this brief article, I am going to explain how context works in a Go application. I will not enter into too many details of it but I will leave you this link for more information.

High-Level Overview

From a very high-level perspective, a Context can be compared to an n-ary tree data structure. Check this diagram below:

In this article, I will only take into account Go context WithCancel, which seems quite promising.

Context With Cancel

When a cancel signal to a context is emitted all the goroutines listening to the context are interrupted.

If the parent context has emitted the cancel signal, then all the sub-contexts derived from the parent context also receive the cancel signal and thus all goroutines listening on the context/s (parent & sub-context) are also interrupted.

Okay. Let's check the use cases.

Scenario 1

Scenario 1

What is happening in the above diagram?

Goroutines 1,2 and 3 are using the same context.

Goroutines 2 & 3 are listening for any cancellation signal in the context using <-ctx.Done channel.

Goroutine 1 has emitted the cancel signal and immediately goroutines 2 & 3 are interrupted.

Scenario 2

Now, let's check a different scenario.

Scenario 2

Goroutine 1 is working in a different context from the goroutines 2 & 3.

The context for the goroutines 2 & 3 are not derived from the context of goroutine 1.

Now, if goroutine 1 emits a cancellation event, will goroutines 2 & 3 be interrupted?

The answer is NO.

Scenario 3

Scenario 3

Goroutine 1 is working in a different context from the goroutines 2 & 3.

The context for the goroutines 2 & 3 are DERIVED from the context of goroutine 1.

Now, if goroutine 1 emits a cancellation event, will goroutines 2 & 3 be interrupted?

The answer is hell YES.

Scenario 4

What will happen if the cancellation event is emitted for the root context?

Well, in that case, all the goroutines will be interrupted. It's awesome, right? I mean damn awesome.

Show me some code

Definitely. Below is my code logic in a pictorial view.

Code snipped diagram 1

I have two stages, stage 1 & stage 2.

I have created ctxCancelStage1 for stage 1 derived from the root context.

Now, I have created another context ctxCancelStage2 derived from ctxCancelStage1 for stage 2.

Stage 1 is producing some data on channel data and stage 2 is reading data from the same channel.

Stage 1 is emitting a cancel signal for ctxCancelStage1 and consequently, the goroutine (worker) in stage 2 is listening to the event and processing accordingly. In the demo code, it's only exiting the loop to stop processing data.

Check the Github code:

On execution of the code, you should see the below output.

Now, let's tweak the code a bit.

Here, I have created the ctxCancelStage2 derived from the root context. Stage 2 is working with this context.

Triggered the cancel event on ctxCancelStage1.

Will Stage 2 be interrupted?

The answer is NO. In the demo code, the worker in stage 2 continues in the infinite for loop. (Memory leak).

Below is the result.

Conclusion

In this brief article, I have explained the use case of Context in Go. I find it extremely useful while working for concurrent request processing. Hope this article has helped anyone naive like me to figure out how context works.

Happy Go learning!

--

--