DevPrep
  • Interview Prep
  • Projects
  • Resources
  • Pricing
  • About Us
Submit Question
DevPrep
  • Pricing
  • About Us
Submit Question

Practice

  • JavaScript
  • DSA
  • Machine Coding
  • System Design

Resources

  • Learning Tracks
  • Articles
  • Roadmaps
  • Compare Concepts
  • Glossary
  • Developer Tools
  • All Questions

Company

  • About
  • Pricing

Legal

  • Privacy Policy
  • Terms of Service
DevPrep

© 2026 DevPrep. All rights reserved.

← Back to Questions
MediumTheory

Production HTTP Client Configuration in Go

61 views

Problem Statement

The default http.DefaultClient has no timeout and poor connection pool settings. Configure a production-ready HTTP client that won't leak connections or hang forever.

The Default Client Trap

// ❌ NEVER use in production
resp, err := http.Get("https://slow-api.com/data")
// If server never responds, this blocks FOREVER
// No timeout, no connection limit

Production HTTP Client

import (
    "net"
    "net/http"
    "time"
)

func NewHTTPClient() *http.Client {
    transport := &http.Transport{
        // Connection pool settings
        MaxIdleConns:        100,              // Total idle connections
        MaxIdleConnsPerHost: 10,               // Per-host idle connections
        MaxConnsPerHost:     100,              // Max connections per host
        IdleConnTimeout:     90 * time.Second, // Close idle connections
        
        // Timeouts for connection establishment
        DialContext: (&net.Dialer{
            Timeout:   30 * time.Second, // Connection timeout
            KeepAlive: 30 * time.Second, // TCP keepalive
        }).DialContext,
        
        // TLS handshake timeout
        TLSHandshakeTimeout: 10 * time.Second,
        
        // Response header timeout
        ResponseHeaderTimeout: 10 * time.Second,
        
        // Expect: 100-continue timeout
        ExpectContinueTimeout: 1 * time.Second,
    }
    
    return &http.Client{
        Transport: transport,
        Timeout:   30 * time.Second, // Total request timeout
    }
}

Connection Pool Sizing

// If you talk to ONE microservice heavily:
transport := &http.Transport{
    MaxIdleConnsPerHost: 100, // Increase from default 2!
    MaxConnsPerHost:     100,
}

// If you talk to MANY different hosts:
transport := &http.Transport{
    MaxIdleConns: 1000, // Total pool size
    MaxIdleConnsPerHost: 10,
}

Request-Level Timeout with Context

func fetchWithTimeout(client *http.Client, url string) ([]byte, error) {
    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancel()
    
    req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
    if err != nil {
        return nil, err
    }
    
    resp, err := client.Do(req)
    if err != nil {
        if ctx.Err() == context.DeadlineExceeded {
            return nil, fmt.Errorf("request timed out")
        }
        return nil, err
    }
    defer resp.Body.Close()
    
    return io.ReadAll(resp.Body)
}

Common Production Issues

IssueCauseFix
Connection leakNot closing resp.BodyAlways defer resp.Body.Close()
Too many TIME_WAITLow MaxIdleConnsPerHostIncrease to 10-100
Request hangsNo timeout setSet Client.Timeout
DNS staleCached DNS entriesLimit connection age

Sample Test Cases

Case 1
Input
client.Timeout = 30s
Expected Output
Request fails after 30 seconds
Case 2
Input
Transport.MaxIdleConnsPerHost = 10
Expected Output
Reuses up to 10 connections per host

No solutions yet

Be the first to share a solution for this question.

Comments (0)

Sign in to leave a comment.

No comments yet. Be the first to comment.

Stats

Views
61
Likes
0
Solutions
0
Comments
0

Category

Backend Engineering

Languages

Go