While working on a simple monitoring library, I came across an issue of wanting to cancel a goroutine when it's context is cancelled, but the way I was using time.Sleep in my code meant that it would wait until the next tick of the interval to respect the context cancellation (because priority would be held up in the default block of my switch statement, and the
<-ctx.Done() receive wouldn't happen until the next iteration of my
for select loop.
The solution for me was to use a ticker and select over both the context cancel or the ticker, but in researching this solution I discovered that there is a fundamental difference in how goroutines handle
time.Sleep will let the goroutine enter a "sleeping" sub-state, but
time.After will crucially let the goroutine enter blocking state. This has subtle implications for thread handling that one should be aware of when using long-living goroutines (or really goroutines at all).