Skip to content

Instantly share code, notes, and snippets.

@wjkoh
Last active May 5, 2025 05:40
Show Gist options
  • Save wjkoh/c91cac5fa35dc30523371b10ca91e31a to your computer and use it in GitHub Desktop.
Save wjkoh/c91cac5fa35dc30523371b10ca91e31a to your computer and use it in GitHub Desktop.
Go: How to Run an HTTP Server Correctly
package main
import (
"context"
"embed"
"html/template"
"log"
"log/slog"
"net"
"net/http"
"os"
"os/signal"
"strconv"
"syscall"
"time"
)
var (
//go:embed templates
templatesFs embed.FS
templates = template.Must(template.ParseFS(templatesFs, "*.html"))
)
func main() {
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer cancel()
if err := run(ctx, "", 8080); err != nil {
log.Fatal(err)
}
}
func run(ctx context.Context, host string, port int) error {
addr := net.JoinHostPort(host, strconv.Itoa(port))
root := http.NewServeMux()
root.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
if err := templates.ExecuteTemplate(w, "landing.html", nil); err != nil {
slog.Error("ExecuteTemplate failed", "name", "landing.html", "err", err)
}
})
s := &http.Server{
Addr: addr,
Handler: root,
}
errCh := make(chan error, 1)
go func() { errCh <- s.ListenAndServe() }()
select {
case err := <-errCh:
return err
case <-ctx.Done():
slog.Info("Shutdown called")
defer slog.Info("Shutdown returned")
shutdownCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
return s.Shutdown(shutdownCtx)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment