cfg.MaxWait { sleep = cfg.MaxWait } select { case <-time.After(sleep): case <-ctx.Done(): return fmt.Errorf("retry cancelled: %w", ctx.Err()) } wait = time.Duration(float64(wait) * cfg.Multiplier) } } func isRetryable(err error) bool { // Only retry transient errors code := status.Code(err) return code == codes.Unavailable || code == codes.DeadlineExceeded || code == codes.ResourceExhausted } // Idempotency key for non-idempotent operations func (s *userServiceServer) CreateUser( ctx context.Context, req *pb.CreateUserRequest, ) (*pb.User, error) { // Extract idempotency key from metadata md, _ := metadata.FromIncomingContext(ctx) idempKey := md.Get("idempotency-key") // Check if we've seen this key before if len(idempKey) > 0 { if cached, err := s.cache.Get(ctx, "idemp:"+idempKey[0]); err == nil { var existing pb.User proto.Unmarshal(cached, &existing) return &existing, nil // return cached response } } // ... create user, cache result with idempotency key }"> cfg.MaxWait { sleep = cfg.MaxWait } select { case <-time.After(sleep): case <-ctx.Done(): return fmt.Errorf("retry cancelled: %w", ctx.Err()) } wait = time.Duration(float64(wait) * cfg.Multiplier) } } func isRetryable(err error) bool { // Only retry transient errors code := status.Code(err) return code == codes.Unavailable || code == codes.DeadlineExceeded || code == codes.ResourceExhausted } // Idempotency key for non-idempotent operations func (s *userServiceServer) CreateUser( ctx context.Context, req *pb.CreateUserRequest, ) (*pb.User, error) { // Extract idempotency key from metadata md, _ := metadata.FromIncomingContext(ctx) idempKey := md.Get("idempotency-key") // Check if we've seen this key before if len(idempKey) > 0 { if cached, err := s.cache.Get(ctx, "idemp:"+idempKey[0]); err == nil { var existing pb.User proto.Unmarshal(cached, &existing) return &existing, nil // return cached response } } // ... create user, cache result with idempotency key }" />

Prev Next

Golang / GoLang System Architecture and Testing Interview Questions

How do you implement safe retries in Go microservices?

Retries improve resilience but must be done correctly. Retrying non-idempotent operations (POST create) without idempotency keys causes duplicate records. Retrying without backoff causes thundering herd. Retrying infinite times causes cascading failure.

// Safe retry with exponential backoff and jitter
type RetryConfig struct {
    MaxAttempts int
    InitialWait time.Duration
    MaxWait     time.Duration
    Multiplier  float64
}

func Retry(ctx context.Context, cfg RetryConfig, fn func() error) error {
    wait := cfg.InitialWait
    for attempt := 1; ; attempt++ {
        err := fn()
        if err == nil { return nil }

        // Don't retry permanent errors
        if !isRetryable(err) { return err }

        if attempt >= cfg.MaxAttempts {
            return fmt.Errorf("after %d attempts: %w", attempt, err)
        }

        // Exponential backoff with jitter
        jitter := time.Duration(rand.Int63n(int64(wait / 2)))
        sleep := wait + jitter
        if sleep > cfg.MaxWait { sleep = cfg.MaxWait }

        select {
        case <-time.After(sleep):
        case <-ctx.Done():
            return fmt.Errorf("retry cancelled: %w", ctx.Err())
        }
        wait = time.Duration(float64(wait) * cfg.Multiplier)
    }
}

func isRetryable(err error) bool {
    // Only retry transient errors
    code := status.Code(err)
    return code == codes.Unavailable ||
        code == codes.DeadlineExceeded ||
        code == codes.ResourceExhausted
}

// Idempotency key for non-idempotent operations
func (s *userServiceServer) CreateUser(
    ctx context.Context, req *pb.CreateUserRequest,
) (*pb.User, error) {
    // Extract idempotency key from metadata
    md, _ := metadata.FromIncomingContext(ctx)
    idempKey := md.Get("idempotency-key")

    // Check if we've seen this key before
    if len(idempKey) > 0 {
        if cached, err := s.cache.Get(ctx, "idemp:"+idempKey[0]); err == nil {
            var existing pb.User
            proto.Unmarshal(cached, &existing)
            return &existing, nil // return cached response
        }
    }
    // ... create user, cache result with idempotency key
}
Why should retries use exponential backoff with jitter instead of fixed intervals?
What is an idempotency key and why is it necessary for retries on mutating operations?

Invest now in Acorns!!! 🚀 Join Acorns and get your $5 bonus!

Invest now in Acorns!!! 🚀
Join Acorns and get your $5 bonus!

Earn passively and while sleeping

Acorns is a micro-investing app that automatically invests your "spare change" from daily purchases into diversified, expert-built portfolios of ETFs. It is designed for beginners, allowing you to start investing with as little as $5. The service automates saving and investing. Disclosure: I may receive a referral bonus.

Invest now!!! Get Free equity stock (US, UK only)!

Use Robinhood app to invest in stocks. It is safe and secure. Use the Referral link to claim your free stock when you sign up!.

The Robinhood app makes it easy to trade stocks, crypto and more.


Webull! Receive free stock by signing up using the link: Webull signup.

More Related questions...

Compare REST/JSON with gRPC/Protocol Buffers. When would you choose gRPC for a Go microservice? How do you implement a gRPC server in Go, including error handling and interceptors? How do you build a production-ready gRPC client in Go with connection reuse and resilience? What microservice design patterns are most important to understand for Go interviews? How do you implement distributed tracing and observability in a Go microservice system? How do you implement event-driven communication between Go microservices using message queues? How do you manage database connections and sharding in a high-scale Go service? What caching strategies do you use in Go microservices and how do you prevent cache stampede? What are table-driven tests in Go and why are they the standard testing pattern? How do you write Go benchmarks and what does -benchmem tell you? How do you find and fix memory allocation hotspots in a Go service using profiling? How do you structure integration tests in Go that require real databases or external services? Explain the difference between mocks, stubs, and fakes in Go testing. When do you use each? How does Go's built-in fuzzing work and when should you use property-based testing? How do you test concurrent Go code correctly — including data races and timing issues? How do you decide where to draw service boundaries when decomposing a Go monolith into microservices? How do you version gRPC APIs in Go without breaking existing clients? How do you write unit and integration tests for gRPC services in Go? How do you load test a Go microservice and interpret the results? How does service discovery and client-side load balancing work in a Go microservice system? How do you design a consistent error model across multiple Go microservices? How do you implement the Saga pattern for distributed transactions in Go? What testing.T methods do experienced Go engineers use to write cleaner tests? How do you benchmark concurrent code with testing.B and what insights does it provide? How do you manage dependency injection at scale in a large Go service — wire, dig, or manual? How do you achieve zero-downtime deployments for a Go microservice in Kubernetes? How do generics in Go 1.18+ enable better system design and what are the trade-offs? How do you use test coverage meaningfully in Go — beyond just a percentage? What are the best practices for designing Protocol Buffer schemas in Go microservices? How do you implement safe retries in Go microservices? What are golden file tests in Go and when should you use them? How do you ensure data consistency across Go microservices without distributed transactions? What is the API Gateway pattern and how does it complement Go microservices? What memory leak patterns in Go are not goroutine leaks and how do you detect them? How do CQRS and event sourcing apply to Go microservice architecture? What is chaos engineering and how do Go teams apply it to test microservice resilience? What is contract testing and how does it apply to Go microservices? What makes a Go microservice horizontally scalable and what patterns break scaling? How do you implement configuration hot-reloading in a Go service without restart? How do you architect Go services for maximum testability at the package level? How do you implement feature flags and canary deployments in a Go microservice? How do you design a multi-tenant Go microservice? What is mutation testing and how does it evaluate test suite quality beyond coverage? How do you manage the full lifecycle of a Go microservice from startup to shutdown? How do you test Go code that processes streaming data or works with channels? Summarise the key principles for designing scalable Go microservices that senior engineers demonstrate.
Show more question and Answers...


Comments & Discussions