This is just a quick footnote regarding the differences in handling timeouts between Go and Python.

To begin with, my exploration started when i attempted to make an simple HTTP request using the built-in net/http package in Go, and hit with a specific API. It’s surprised me since i received an unexpected response stating “context deadline exceeded.” This piqued my curiosity, as i wondered why this error occurred. Interestingly, when i tried to hit to the same API through Postman or a simple Python script, i encountered no issues.

Furthermore, i learned that the "context deadline exceeded" error arises when the context for sending an HTTP request is canceled due to reaching a specified timeout. While this explanation may seem straightforward and simple, going deeper into the subject can reveal its intriguing complexity, especially when considering different scenarios.

Context-matters when handling timeout

Basically, when making an HTTP request in Go using the net/http package, the process heavily relies on the “context” package. This context is passed along during the entire lifecycle of the HTTP request and response.

For instance, let’s say you set a timeout duration of 1 second. The timeout process will be propagated into several stages. First, there’s a connection dialing process, which might take around 0.5 seconds. Then, there’s the TLS/SSL handshake, which could also take 0.5 seconds. If during these stages the server-side response headers haven’t been received, the “context deadline exceeded” message is raised.

The concept of “context” itself is crucial in propagating the lifecycle of the HTTP request. It’s mostly responsible for handling the cancellation process when the timeout is exceeded. By using this approach, Go net/http ensures consistent and unified timeout handling, allowing for multiple requests from the same client to be managed effectively.

    // set the timeout values to 0. Suprisingly, when you set the
    // timeout values to 1-2 second, you will still get the error
	ctx, cancel := context.WithTimeout(context.Background(), 0)
	defer cancel()
 
	req, _ := http.NewRequestWithContext(ctx, "GET", "https://jsonplaceholder.typicode.com/posts/2", nil)
 
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		log.Fatalf("there's something wrong making a request %s \n", err)
        // with this, you will be able to trace whether
        // you get the context deadline exceeding message
		if errors.Is(err, context.DeadlineExceeded) {
			log.Fatalf("context exceeding status is : true")
		}
	}

Python’s requests approach

That being said, there are differences when making an HTTP request using Python’s requests compared to Go’s net/http package. In Go, when using the http.NewRequest method, it’s already wrapped with http.NewRequestWithContext method, which has a default timeout set. This means that even if you don’t explicitly set a timeout, you won’t encounter an error.

On the other hand, in Python’s requests, the timeout isn’t implicitly set or globally defined because the HTTP request lifecycle process is different. When you set a timeout parameter, such as 5 seconds, you will experience a timeout if you haven’t received a response from the server within that 5 seconds delay. However, in Python, even if a timeout occurs, the HTTP request process will continue to execute and not stop.

In summary, the design and handling of timeout is differ between Go and Python. Go provides more granular control over timeouts, while in Python, the timeout settings are left to the developer’s need based on their specific requirements (or based on request per basis)