The context package in go provides a path to cancel and propagate cancelling information around the methods and even across http servers.
Consider you request your server with some information but want to cancel that request halfway, or maybe somehow the connection get drops. The ability to propagate that information to server and trigger cancellation of that request will save you lot of computations.
The below code is in example implementation of exactly this.
Server Code
package main
import (
"fmt"
"log"
"net/http"
"time"
)
func main() {
http.HandleFunc("/", rootHandler)
log.Fatal(http.ListenAndServe("localhost:8080", nil))
}
func rootHandler(w http.ResponseWriter, r *http.Request) {
log.Printf("handler started")
defer log.Printf("handler ended")
// access context here
ctx := r.Context()
// selecting if our work got done of context was cancelled
select {
case <-time.After(5 * time.Second):
fmt.Fprintln(w, "hello")
case <-ctx.Done():
log.Printf("context reached, %s", ctx.Err().Error())
http.Error(w, ctx.Err().Error(), http.StatusInternalServerError)
}
}
Now let’s look how we can actually cancel the context
Client Code
package main
import (
"context"
"io"
"log"
"net/http"
"os"
"time"
)
func main() {
// create context and add cancel context to it, calling cancel will trigger ctx
// which can be interpreted on server side
ctx := context.Background()
ctx, cancel := context.WithCancel(ctx)
time.AfterFunc(time.Second, cancel)
// creating request to attach ctx to it
req, err := http.NewRequest(http.MethodGet, "http://localhost:8080", nil)
if err != nil {
log.Printf("error: request made: %v", err)
}
req = req.WithContext(ctx)
// executing the request
resp, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatalf("error while getting, %v", err)
}
if resp.StatusCode != http.StatusOK {
log.Fatalf("error: response, %v", resp.Body)
}
defer resp.Body.Close()
io.Copy(os.Stdout, resp.Body)
}
By calling cancel we quickly getting the response back from server without the 5 second delay.
Passing Values in Ctx
Context package gives the ability to pass values in the context as well.
Rule of thumb while passing values, the value should have the impact on how the program behaves. A good example could be passing uuid’s, request’ids.