Go

What is wrong with this handler? What error will the goroutine see?

Question 276HardGo 1.22 to 1.25
func handler(w http.ResponseWriter, r *http.Request) {
	go func() {
		// sends an audit event to another service
		if err := sendAudit(r.Context(), r.URL.Path); err != nil {
			log.Println("audit:", err)
		}
	}()
	w.WriteHeader(http.StatusAccepted)
}

The request context is canceled when ServeHTTP returns. The handler returns almost immediately, so the goroutine's outgoing HTTP call usually fails with context canceled, sometimes before it even dials. The bug is timing-dependent: it may pass locally and then fail under load, or the other way round.

Two more problems:

  • Touching r after the handler returns is not allowed (the server may reuse parts of it), and reading r.Body after return is definitely broken. Copy what you need first.
  • Nothing bounds or tracks the goroutine: it has no timeout and no shutdown coordination.
func handler(w http.ResponseWriter, r *http.Request) {
	path := r.URL.Path // copy needed data
	ctx, cancel := context.WithTimeout(context.WithoutCancel(r.Context()), 3*time.Second)
	go func() {
		defer cancel()
		if err := sendAudit(ctx, path); err != nil {
			log.Println("audit:", err)
		}
	}()
	w.WriteHeader(http.StatusAccepted)
}

In production, prefer a bounded worker pool or queue that drains during graceful shutdown over one goroutine per request.

More on Context

All 35 Context questions