Purpose of TimeoutHandler

513 views
Skip to first unread message

Amit Saha

unread,
Apr 18, 2021, 7:10:37 PM4/18/21
to golang-nuts
Hi all - I wrongly assumed that the TimeoutHandler() is supposed to help application authors free up resources on the sever for anything running than the expected duration of time. However that doesn’t seem to be the case. The inner handler continues running, only the client gets a 503 after the duration is expired.

So, I guess have two queries:

1. What is the purpose of TimeoutHandler? Is it to just let the client know that their request couldn’t be completed and they should just try again?
2. Is there currently another standard library provided solution to wrap a handler which will terminate the inner handler function when the duration expires?

Thanks,
Amit.


Brian Candler

unread,
Apr 19, 2021, 4:02:32 AM4/19/21
to golang-nuts
Your inner request handler needs to use the request context to cancel its work.

package main

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

type foo struct{}

func (f foo) ServeHTTP(w http.ResponseWriter, r *http.Request) {
log.Print("New request")
for i := 0; i < 10; i++ {
select {
case <-r.Context().Done():
log.Print("Aborted")
return
case <-time.After(1 * time.Second):
log.Print("Tick")
}
w.Write([]byte(".\n"))
}
w.Write([]byte("hello world\n"))
log.Print("Completed")
}

func main() {
fooHandler := foo{}
timeoutHandler := http.TimeoutHandler(fooHandler, 5*time.Second, "Too slow!\n")
http.Handle("/foo", timeoutHandler)
log.Fatal(http.ListenAndServe(":8080", nil))
}

To test:
curl localhost:8080/foo

Amit Saha

unread,
Apr 19, 2021, 8:08:57 AM4/19/21
to Brian Candler, golang-nuts
Thank you, I was suspecting that this might be the way to do it.




--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/d75657a2-5ab5-4908-9997-3fe3dfe3b87an%40googlegroups.com.

Amit Saha

unread,
Apr 24, 2021, 5:05:24 AM4/24/21
to Brian Candler, golang-nuts

On 19 Apr 2021, at 10:07 pm, Amit Saha <amits...@gmail.com> wrote:

Thank you, I was suspecting that this might be the way to do it.

This is another approach I thought would also work without using channels or where you are just running a sequence of steps in a handler:

func handleUserAPI(w http.ResponseWriter, r *http.Request) {
log.Println("I started processing the request")
time.Sleep(15 * time.Second)

log.Println("Before continuing, i will check if the timeout has already expired")
if r.Context().Err() != nil {
log.Printf("Aborting further processing: %v\n", r.Context().Err())
return
}
fmt.Fprintf(w, "Hello world!")
log.Println("I finished processing the request")
}



Brian Candler

unread,
Apr 24, 2021, 5:39:34 AM4/24/21
to golang-nuts
That works too.  Err() is guaranteed to return non-nil, either if the context was explicitly cancelled or its deadline was exceeded.
Reply all
Reply to author
Forward
0 new messages