Skip to content

Enhanced Timeout Middleware #1003

@Andrei-hub11

Description

@Andrei-hub11

Summary

Add configurable timeout middleware with per-route timeouts, path exclusions, and custom timeout handlers while maintaining full backward compatibility with existing Timeout() function.

Motivation

Current timeout middleware limitations:

  • Global timeout for all routes
  • Cannot skip specific paths (health checks, uploads, webhooks)
  • Fixed 504 Gateway Timeout response
  • No per-route timeout configuration

Proposed Solution

Add TimeoutWithConfig function following Chi's established middleware patterns:

type TimeoutConfig struct {
    // Timeout defines the default timeout duration
    Timeout time.Duration
    
    // OnTimeout is called when a timeout occurs (optional)
    OnTimeout func(w http.ResponseWriter, r *http.Request)
    
    // SkipPaths defines paths that should ignore timeout
    SkipPaths []string
    
    // PerRoute allows specific timeouts per route pattern
    PerRoute map[string]time.Duration
    
    // Skip defines a function to conditionally skip timeout
    Skip func(r *http.Request) bool
}

func TimeoutWithConfig(config TimeoutConfig) func(next http.Handler) http.Handler

Usage Examples

Basic Configuration (same as current)

r.Use(middleware.TimeoutWithConfig(middleware.TimeoutConfig{
    Timeout: 30 * time.Second,
}))

Per-Route Timeouts

r.Use(middleware.TimeoutWithConfig(middleware.TimeoutConfig{
    Timeout: 5 * time.Second,
    PerRoute: map[string]time.Duration{
        "/api/reports/*": 30 * time.Second,
        "/api/upload/*":  60 * time.Second,
    },
}))

Skip Specific Paths

r.Use(middleware.TimeoutWithConfig(middleware.TimeoutConfig{
    Timeout: 5 * time.Second,
    SkipPaths: []string{"/health", "/metrics", "/ping"},
}))

Custom Timeout Response

r.Use(middleware.TimeoutWithConfig(middleware.TimeoutConfig{
    Timeout: 5 * time.Second,
    OnTimeout: func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Content-Type", "application/json")
        w.WriteHeader(http.StatusRequestTimeout)
        json.NewEncoder(w).Encode(map[string]interface{}{
            "error":   "Request timeout",
            "path":    r.URL.Path,
            "timeout": "5s",
        })
    },
}))

Backward Compatibility

The existing Timeout(timeout time.Duration) function remains unchanged and fully compatible. New functionality is purely additive.

Benefits

  • Zero breaking changes
  • Flexible per-route configuration
  • Custom timeout responses
  • Skip health checks and uploads
  • Follows Chi's middleware patterns

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions