Skip to content

Instantly share code, notes, and snippets.

@renthraysk
Last active June 24, 2020 19:12
Show Gist options
  • Save renthraysk/cf01be2d6b6f9e9cfcce6d5304618291 to your computer and use it in GitHub Desktop.
Save renthraysk/cf01be2d6b6f9e9cfcce6d5304618291 to your computer and use it in GitHub Desktop.
Cancellation
package main
import (
"context"
"errors"
"fmt"
"log"
"net"
"net/http"
"os"
"os/signal"
"time"
)
type contextKey string
const (
ShutdownContextKey = contextKey("shutdown")
)
func main() {
errCh := make(chan error)
sigCh := make(chan os.Signal)
signal.Notify(sigCh, os.Interrupt)
ctx := context.Background()
shutdownCtx, cancel := context.WithCancel(ctx)
ctx = context.WithValue(ctx, ShutdownContextKey, shutdownCtx)
s := &http.Server{
Addr: ":8080",
Handler: &Long{},
BaseContext: func(_ net.Listener) context.Context { return ctx },
}
s.RegisterOnShutdown(cancel)
go func() { errCh <- s.ListenAndServe() }()
// Main loop
var err error
for err == nil {
select {
case s := <-sigCh:
switch s {
case os.Interrupt:
err = errors.New(s.String())
}
case err = <-errCh:
}
}
// Shutdown
{
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
if err := s.Shutdown(ctx); err != nil {
log.Printf("error during shutdown: %v", err)
}
cancel()
}
if err != nil {
log.Printf("shutdown: %v", err)
os.Exit(1)
}
os.Exit(0)
}
type Long struct{}
func (Long) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
return
}
f, ok := w.(http.Flusher)
if !ok {
http.Error(w, "Streaming events not supported", http.StatusBadRequest)
return
}
w.Header().Set("Content-Type", "text/event-stream")
w.Header().Set("Cache-Control", "no-cache")
w.Header().Set("Transfer-Encoding", "chunked")
ctx := r.Context().Value(ShutdownContextKey).(context.Context)
t := time.NewTicker(time.Second)
defer t.Stop()
for {
f.Flush()
select {
case <-t.C:
fmt.Fprintf(w, "type: ping\n\n")
case <-r.Context().Done(): // Client gone
return
case <-ctx.Done(): // Server shutting down
fmt.Fprintf(w, "type: shutdown\n\n")
f.Flush()
return
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment