1. 26
  1. 8

    Good overview 👍 Although I think the part about the TimeoutHandler() etc. is a bit redundant now that we have context? As far as I know, it can replace all use cases?

    One thing that might be worth mentioning is that you usually shouldn’t pass the same context to a goroutine. For example:

    func handle(w ResponseWriter, r *Request) {
        ctx, cancel := WithTimeout(r.Context())
        defer cancel()
        // ...
        go sendmail(r.Context(), ...)
        // ...

    This usually works most of the time on the dev environment since the mock email is probably fast, but on production it might take a second or two (hence the goroutine) and it will be cancelled before it finishes.

    This is especially subtle if you add a timeout on the request context in the middleware, so you’re used to using r.Context().

    You’ll need to use a new context.Background() (or create a new one with the appropriate values, if you use contexts like that).

    Just something I’ve seen several people do wrong over the years (and have done wrong myself once or twice as well 😅).

    1. 1

      I like your example with r.Context and a goroutine. Another gotcha in this situation is that deferred cancel func will be called on handler function exit. So using timeout + cancel + goroutine is not obvious for newcomers.