Lab 06: Distributed Patterns

Time: 45 minutes | Level: Advanced | Docker: docker run -it --rm golang:1.22-alpine sh

Overview

Implement production-grade distributed system patterns: circuit breaker (gobreaker), retry with exponential backoff + jitter, token bucket rate limiter, bulkhead pattern, and health check endpoints.


Step 1: Circuit Breaker with gobreaker

The circuit breaker prevents cascading failures by stopping calls to a failing service.

States:  Closed ──(failures≥threshold)──► Open
         Open   ──(timeout elapsed)─────► Half-Open
         Half-Open ──(success)──────────► Closed
         Half-Open ──(failure)──────────► Open
package main

import (
	"errors"
	"fmt"
	"time"

	"github.com/sony/gobreaker"
)

func setupCircuitBreaker() *gobreaker.CircuitBreaker {
	settings := gobreaker.Settings{
		Name:        "product-service",
		MaxRequests: 3,                // max requests in half-open state
		Interval:    10 * time.Second, // count window
		Timeout:     5 * time.Second,  // time in open state
		ReadyToTrip: func(counts gobreaker.Counts) bool {
			// Trip after 3 consecutive failures
			return counts.ConsecutiveFailures >= 3
		},
		OnStateChange: func(name string, from gobreaker.State, to gobreaker.State) {
			fmt.Printf("  ⚡ Circuit '%s': %s%s\n", name, from, to)
		},
	}
	return gobreaker.NewCircuitBreaker(settings)
}

func callService(cb *gobreaker.CircuitBreaker, fail bool) (string, error) {
	result, err := cb.Execute(func() (interface{}, error) {
		if fail {
			return nil, errors.New("service unavailable")
		}
		return "ok", nil
	})
	if err != nil {
		return "", err
	}
	return result.(string), nil
}

Step 2: State Transition Demo


Step 3: Retry with Exponential Backoff + Jitter


Step 4: Rate Limiter — Token Bucket


Step 5: Bulkhead Pattern — Semaphore


Step 6: Health Check Endpoint


Step 7: Complete Integration


Step 8: Capstone — Full Demo

📸 Verified Output:


Summary

Pattern
Library
Problem Solved

Circuit Breaker

github.com/sony/gobreaker

Prevent cascading failures

Retry + Backoff

stdlib + math

Transient failure recovery

Token Bucket

golang.org/x/time/rate

Rate limiting

Bulkhead

semaphore (channels)

Resource isolation

Health Check

net/http

Kubernetes liveness/readiness

Key Takeaways:

  • Circuit breaker: trip fast, recover gradually (Closed→Open→Half-Open→Closed)

  • Full jitter beats equal jitter for thundering herd prevention

  • Rate limiters protect servers; bulkheads protect clients

  • Combine patterns: circuit breaker + retry + rate limiter for resilient services

  • /health for liveness (is it running?), /ready for readiness (can it serve traffic?)

Last updated