Skip to content

Go — Practical

package main
import (
"context"; "errors"; "log"; "net/http"
"os"; "os/signal"; "syscall"; "time"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("ok"))
})
srv := &http.Server{
Addr: ":8080", Handler: mux,
ReadHeaderTimeout: 5 * time.Second,
}
go func() {
if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
log.Fatalf("listen: %v", err)
}
}()
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
if err := srv.Shutdown(ctx); err != nil {
log.Fatalf("shutdown: %v", err)
}
}
func workerPool[T, R any](ctx context.Context, n int, jobs <-chan T, fn func(T) R) <-chan R {
out := make(chan R)
var wg sync.WaitGroup
for i := 0; i < n; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for {
select {
case <-ctx.Done():
return
case j, ok := <-jobs:
if !ok { return }
out <- fn(j)
}
}
}()
}
go func() { wg.Wait(); close(out) }()
return out
}

errgroup for parallel work with cancellation

Section titled “errgroup for parallel work with cancellation”
import "golang.org/x/sync/errgroup"
g, ctx := errgroup.WithContext(ctx)
for _, url := range urls {
url := url
g.Go(func() error {
req, _ := http.NewRequestWithContext(ctx, "GET", url, nil)
resp, err := http.DefaultClient.Do(req)
if err != nil { return err }
defer resp.Body.Close()
return nil
})
}
if err := g.Wait(); err != nil {
return err
}
func retry(ctx context.Context, max int, fn func() error) error {
var err error
for i := 0; i < max; i++ {
if err = fn(); err == nil { return nil }
wait := time.Duration(math.Pow(2, float64(i))) * 100 * time.Millisecond
select {
case <-time.After(wait):
case <-ctx.Done():
return ctx.Err()
}
}
return err
}
import "golang.org/x/sync/singleflight"
var g singleflight.Group
val, err, _ := g.Do(key, func() (any, error) {
return expensiveLookup(key)
})
import "golang.org/x/time/rate"
lim := rate.NewLimiter(rate.Every(time.Second), 10) // 10/sec, burst 10
if err := lim.Wait(ctx); err != nil { /* ctx canceled */ }
type Cache struct {
mu sync.RWMutex
m map[string]string
}
func (c *Cache) Get(k string) (string, bool) {
c.mu.RLock(); defer c.mu.RUnlock()
v, ok := c.m[k]
return v, ok
}
func (c *Cache) Set(k, v string) {
c.mu.Lock(); defer c.mu.Unlock()
c.m[k] = v
}
db, err := sql.Open("postgres", dsn)
if err != nil { return err }
db.SetMaxOpenConns(25); db.SetMaxIdleConns(5); db.SetConnMaxLifetime(5*time.Minute)
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
var name string
err = db.QueryRowContext(ctx, "SELECT name FROM users WHERE id=$1", id).Scan(&name)
import _ "net/http/pprof"
go http.ListenAndServe(":6060", nil) // exposes /debug/pprof/*
Terminal window
go tool pprof http://localhost:6060/debug/pprof/profile?seconds=30
go tool pprof http://localhost:6060/debug/pprof/heap
go tool pprof http://localhost:6060/debug/pprof/goroutine
Terminal window
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o app ./cmd/app
docker build -t app:latest . # use distroless or scratch base for tiny image
func TestAdd(t *testing.T) {
cases := []struct{ a, b, want int }{
{1, 2, 3}, {0, 0, 0}, {-1, 1, 0},
}
for _, c := range cases {
c := c
t.Run(fmt.Sprintf("%d+%d", c.a, c.b), func(t *testing.T) {
t.Parallel()
if got := Add(c.a, c.b); got != c.want {
t.Errorf("got %d want %d", got, c.want)
}
})
}
}
  • HTTP framework: chi, echo, fiber, gin (or stdlib + chi for middleware).
  • DB: pgx, sqlx, sqlc (codegen), gorm.
  • Logging: log/slog (stdlib 1.21+), zap, zerolog.
  • Config: viper, envconfig.
  • Validation: go-playground/validator.
  • Mocking: mockery, gomock.
  • Tracing: go.opentelemetry.io/otel.