
2 min read
Waiting for goroutines
Yesterday we looked at some sample code with goroutines: for i := range 10 { go func() { fmt.Println(i) }() } But if you ran it, you probably saw no output. This is because the main goroutine exits before the 10 new goroutines have a chance to run. How do we solve this? We need some sort of synchronization mechanism in place, to ensure we wait for all goroutines to finish before exiting the program.

3 min read
Goroutines
Today I’m starting a new series of posts on the topic of goroutines. In the past, I’ve mostly walked through existing documentation (the Go spec, docs for standard library packages, etc), and provided my commentary and explanation. Starting today, instead, I’ll be going on a topical journey through goroutines. I will, of course, touch on the spec, and some standard library packages, but I’ll be taking my own path through the topic.

2 min read
Dependency pinning
Today I want to share a trick I stumbled upon. It won’t matter to most of you. If it does matter to you, it will probably save you a bunch of headaches! First, some background. Have you ever had to use an outdated dependency for $REASONS? If not, you can skip today’s email, unless you’re just curious. One of my clients is still using MongoDB 3.2. MongoDB was EOLed more than a year before anyone had ever heard the term “COVID”.

2 min read
Why is context.TODO not just a comment?
I’ve been on vacation for the last week, so haven’t written much. Let’s finally finish up the context package series with some reader feedback and questions! Joost Helberg wrote in with an interesting observation about context.TODO. In his own words: With regards to context.TODO, back in my early Go days, I thought the TODO was about the intent of this context. Like context.Background is for a background task and context.WithCancel for a job that can be canceled.
Subscribe to Boldly Go: Daily
Every day I'll send you advice to improve your understanding of Go. Don't miss out! I will respect your inbox, and honor my privacy policy.
Unsure? Browse the archive.

3 min read
context.WithoutCancel
This is it! The last of the context package functions that we will cover in this series. Well, almost. I actually have a couple reader feedback and question emails to respond to, which I’ll do next, before startinga a new series. Speak of a new series: I’m still looking for suggestions! I have a couple ideas, but I’d rather do something you’re itching to learn about, than whatever random idea I come up with.

2 min read
context.WithValue
func WithValue func WithValue(parent Context, key, val any) Context WithValue returns a derived context that points to the parent Context. In the derived context, the value associated with key is val. Use context Values only for request-scoped data that transits processes and APIs, not for passing optional parameters to functions. The provided key must be comparable and should not be of type string or any other built-in type to avoid collisions between packages using context.

3 min read
context.TODO
We’re almost done going through the context package. What would you like me to cover next? If you have a suggestion, hit reply, and let me know! – func TODO func TODO() Context TODO returns a non-nil, empty Context. Code should use context.TODO when it’s unclear which Context to use or it is not yet available (because the surrounding function has not yet been extended to accept a Context parameter).

2 min read
context.Background
After this detour through context key types, let’s get back to the GoDoc for our context package. Next up: context.Background(): func Background func Background() Context Background returns a non-nil, empty Context. It is never canceled, has no values, and has no deadline. It is typically used by the main function, initialization, and tests, and as the top-level Context for incoming requests. Why would you ever want a context that essentially does nothing?

2 min read
Context key/value utilities
So we’ve finally settled on a suitable type for our context key types: string, or maybe a non-empty struct. We also understand that to guard against key collisions, we need our custom type to be un-exported. type contextKey string const KeyUserID = contextKey("user_id") Now code anywhere in your project can use the context key without fear of collision. Done! Right? I’m sure you know the fact that I’m asking means there’s more we can do.

2 min read
Context key type: Final recommendation
First, a correction! An astute reader pointed out that I made a small mistake in my post on June, 10, with regard to string context keys. My code example showed: type contextKey string const ( KeyUserID = "user_id" KeyTransactionID = "transaction_id" KeyMessageID = "message_id" ) But it should have been: type contextKey string const ( KeyUserID contextKey = "user_id" KeyTransactionID contextKey = "transaction_id" KeyMessageID contextKey = "message_id" ) This is a nasty kind of bug, because the code will continue to work as expected—just without any protection from key collisions!

2 min read
Struct context keys
First off, an apology for being rather unreliable with my “daily” emails. I’m in the middle of some traveling (was in the UK and Netherlands last week, and will be on a US road trip starting tomorrow), so I’m writing when I have a spare moment, which isn’t that often. I’ve been talking about finding the ideal type for a context key. So far I’ve looked at empty structs (e.g. struct{}), integers, and strings.