Coordinating goroutines — errGroup

Ricardo Linck
Level Up Coding
Published in
5 min readDec 13, 2020

--

Coordinating different goroutines to achieve a single goal

Photo by Hunter Harritt on Unsplash

In a previous article I talked about how we can use the context.Context struct to share data and group distinct goroutines. One thing that’s missing from that article, is how to synchronise that group of things. Synchronise concurrent tasks means either wait for all of them to finish before doing something else, or cancelling all of them in case things go wrong. That’s where the sync/errgroup comes to the scene. Here are the official docs for the package. The package name conveys two things: used to synchronise, and we are going to be dealing with errors. That pretty much matches what was mentioned above, right? The name errgroup may sound a bit weird as the mechanism to synchronise goroutines, but bear with me, it will make sense later. Essentially you will be registering goroutines to that group and wait for them to finish, one way or the other. The main struct inside the package is the errgroup.Group.

To create a new Group you can call errgroup.WithContext that will receive a context.Context as parameter and return a pointer to a new group and a new context.

There are two methods you will use in this struct:

  • (*errgroup.Group).Go — register a function to the groups and start it as a new goroutine;
  • (*errgroup.Group).Wait — waits until all registered goroutines finish or an error occurs in any goroutine of the group. That’s why it uses the error as the synchronisation mechanism. If an error occurs, the context (that one that was returned by the errgroup.WithContext) gets cancelled and the error gets returned. One thing to pay attention here is that the goroutines that have already started executing will continue to do so, so it’s important to get the context passed along to the goroutine and check if that got cancelled inside the goroutine (usually that’s a simple thing to achieve with the select statement);

This is extremely useful for “scatter and gather” type of problems. As an example, when you receive a request you need to fetch different information for that request from different external sources. In order to improve performance, you can fetch data from each source in a goroutine. That will benefit from concurrency and execute multiple things while waiting for the external…

--

--

Software Engineer. Distributed systems lover, golang and .net enthusiast. Curious by nature. https://github.com/ricardolinck