Golang http TimeoutHandler Function

The http.TimeoutHandler function in Golang is part of the net/http package and is used to wrap an existing HTTP handler with a timeout. This ensures that if the wrapped handler takes longer than a specified duration to process a request, the client will receive a timeout response. This is particularly useful in preventing long-running requests from holding up server resources and providing a better user experience by ensuring timely responses.

Table of Contents

  1. Introduction
  2. http.TimeoutHandler Function Syntax
  3. Examples
    • Basic Usage
    • Custom Timeout Message
    • Using http.TimeoutHandler with Different Handlers
  4. Real-World Use Case
  5. Conclusion

Introduction

The http.TimeoutHandler function allows you to enforce a maximum duration for handling HTTP requests. If the underlying handler does not complete the request within the specified time limit, the TimeoutHandler automatically sends a timeout response to the client. This is useful for ensuring that your server remains responsive even under heavy load or when dealing with potentially slow external services.

http.TimeoutHandler Function Syntax

The syntax for the http.TimeoutHandler function is as follows:

func TimeoutHandler(h http.Handler, dt time.Duration, msg string) http.Handler

Parameters:

  • h: The http.Handler to wrap with a timeout. This is the handler that processes the actual request.
  • dt: The maximum time allowed to process the request. This is specified as a time.Duration.
  • msg: A string containing the message to be sent to the client if the timeout is reached.

Returns:

  • http.Handler: The function returns an http.Handler that enforces the specified timeout when handling requests.

Examples

Basic Usage

This example demonstrates how to use the http.TimeoutHandler function to enforce a timeout on a long-running handler.

Example

package main

import (
	"net/http"
	"time"
)

func main() {
	// Define a handler that simulates a long-running process
	longRunningHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		time.Sleep(5 * time.Second) // Simulate a long process
		w.Write([]byte("Request completed"))
	})

	// Wrap the handler with a timeout of 2 seconds
	timeoutHandler := http.TimeoutHandler(longRunningHandler, 2*time.Second, "Request timed out")

	// Register the handler
	http.Handle("/long", timeoutHandler)

	// Start the server on port 8080
	http.ListenAndServe(":8080", nil)
}

Explanation:

  • The server listens on port 8080.
  • The longRunningHandler simulates a long-running process by sleeping for 5 seconds.
  • The handler is wrapped with http.TimeoutHandler, enforcing a timeout of 2 seconds.
  • If the request takes longer than 2 seconds, the client will receive a "Request timed out" message.

Example Request:

http://localhost:8080/long

Response:

If the request takes longer than 2 seconds, the client will see:

Request timed out

Custom Timeout Message

This example shows how to customize the timeout message sent to the client.

Example

package main

import (
	"net/http"
	"time"
)

func main() {
	// Define a handler that simulates a long-running process
	slowHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		time.Sleep(3 * time.Second) // Simulate a delay
		w.Write([]byte("Slow request completed"))
	})

	// Wrap the handler with a timeout and a custom message
	timeoutHandler := http.TimeoutHandler(slowHandler, 1*time.Second, "Custom Timeout: Request took too long")

	// Register the handler
	http.Handle("/slow", timeoutHandler)

	// Start the server on port 8080
	http.ListenAndServe(":8080", nil)
}

Explanation:

  • The slowHandler simulates a delay of 3 seconds.
  • The handler is wrapped with http.TimeoutHandler, enforcing a timeout of 1 second and a custom timeout message.
  • If the request takes longer than 1 second, the client will receive the custom timeout message.

Example Request:

http://localhost:8080/slow

Response:

If the request takes longer than 1 second, the client will see:

Custom Timeout: Request took too long

Using http.TimeoutHandler with Different Handlers

This example demonstrates how to apply http.TimeoutHandler to different routes in a web server.

Example

package main

import (
	"net/http"
	"time"
)

func main() {
	// Fast handler with no timeout
	http.HandleFunc("/fast", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("Fast request completed"))
	})

	// Slow handler with a timeout of 2 seconds
	slowHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		time.Sleep(5 * time.Second) // Simulate a delay
		w.Write([]byte("Slow request completed"))
	})
	http.Handle("/slow", http.TimeoutHandler(slowHandler, 2*time.Second, "Request timed out"))

	// Start the server on port 8080
	http.ListenAndServe(":8080", nil)
}

Explanation:

  • The /fast route processes requests without a timeout.
  • The /slow route is wrapped with http.TimeoutHandler, enforcing a timeout of 2 seconds.
  • Different routes can have different timeout settings based on their expected processing times.

Example Requests:

  • /fast: This request will complete quickly without any timeout.
  • /slow: If this request takes longer than 2 seconds, it will time out and return a timeout message.

Real-World Use Case

Preventing Slow Requests from Blocking the Server

In a real-world application, http.TimeoutHandler can be used to prevent slow-running requests from consuming server resources and blocking other requests. For example, if you have a web service that performs complex calculations or interacts with slow external APIs, wrapping the handler with http.TimeoutHandler ensures that these operations do not degrade the overall server performance.

Example: Protecting Against Slow External API Calls

package main

import (
	"net/http"
	"time"
)

func main() {
	// Simulate an external API call that could be slow
	externalAPICall := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// Simulate a delay
		time.Sleep(4 * time.Second)
		w.Write([]byte("External API response"))
	})

	// Wrap the handler with a timeout of 2 seconds
	http.Handle("/api", http.TimeoutHandler(externalAPICall, 2*time.Second, "API request timed out"))

	// Start the server on port 8080
	http.ListenAndServe(":8080", nil)
}

Explanation:

  • The server handles requests to /api by simulating an external API call that may take time to respond.
  • To protect against long response times, the handler is wrapped with http.TimeoutHandler with a 2-second timeout.
  • If the external API takes too long, the client receives a timeout message, preventing the request from hanging indefinitely.

Conclusion

The http.TimeoutHandler function in Go is used for managing long-running HTTP requests, ensuring that your server remains responsive even under challenging conditions. By setting appropriate timeouts, you can protect your server from slow requests, enhance user experience by providing timely responses, and maintain overall performance. Whether you're dealing with slow external services or complex internal processing, http.TimeoutHandler provides a simple and effective way to enforce time limits on HTTP requests.

Comments

Spring Boot 3 Paid Course Published for Free
on my Java Guides YouTube Channel

Subscribe to my YouTube Channel (165K+ subscribers):
Java Guides Channel

Top 10 My Udemy Courses with Huge Discount:
Udemy Courses - Ramesh Fadatare