84027

golang server middlerware request cancellation

Question:

I created in the example at the bottom a little server which is running on port 3000. You can access it over "htto://localhost:3000/time". The whole Request is covered with two middlewares. First "cancelHandler" and Second "otherHandler" is called - which is responding with some dummy data after 4 seconds.

<strong>To my problem:</strong> When i request the page in a browser and then cancel the request (before the 4sec). The server is still handling the goroutine/request in the background. I spent already hours to find a solution on google but i can just not wrap my head around the context. (context.WithCancel()) I get that i have to create a chan and listen to it but how does this work with the requests. thats already a goroutine, do i have to create another goroutine in the request/goroutine? Also another question is, should i really use Context for that or is there an easier solution with the cancelNotifier?

Maybe someone can describe it for me and others which maybe have the same understanding problem.

Solution should be that the cancel Handler is stopping the goroutine/request, when the browser cancels the request.

Thank you very much for your time!

package main import ( "log" "net/http" "time" "fmt" ) func otherHandler(format string) http.Handler { fn := func(w http.ResponseWriter, r *http.Request) { time.Sleep(time.Duration(4)*time.Second) tm := time.Now().Format(format) w.Write([]byte("The time is: " + tm)) fmt.Println("response:", "The time is: "+tm) } return http.HandlerFunc(fn) } func cancelHandler(h http.Handler) http.Handler { fn := func(w http.ResponseWriter, r *http.Request) { fmt.Println("start: called cancelHandler") h.ServeHTTP(w, r) fmt.Println("end: called cancelHandler") } return http.HandlerFunc(fn) } func main() { mux := http.NewServeMux() th := otherHandler(time.RFC1123) mux.Handle("/time", cancelHandler(th)) log.Println("Listening...") http.ListenAndServe(":3000", mux) }

Answer1:

The only way to "stop" a function is to return from it. Thus, time.Sleep cannot be interrupted. Use a select statement instead:

package main import ( "fmt" "net/http" "time" ) func main() { http.ListenAndServe(":3000", otherHandler(time.RFC1123)) } func otherHandler(format string) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { select { case <-time.After(4 * time.Second): // time's up case <-r.Context().Done(): // client gave up return } tm := time.Now().Format(format) w.Write([]byte("The time is: " + tm)) fmt.Println("response:", "The time is: "+tm) } }

In general, check the request context (or one that is derived from it) in strategic places. If the context is canceled, don't proceed any further and return.

Recommend

  • Are goroutines garbage collected together with their channels?
  • How can you test code that relies on net.Conn without creating an actual network connection?
  • How to efficiently close the channel?
  • Deep copy Objective C objects with UIImageView as property
  • Prevent focus to URL bar with CTRL + L
  • Handling exceptions in a class library enveloping a device driver
  • Is MVC2 ASP.Net URLDecoding automatically?
  • How to fallback to entirely different index page if user has javascript disable?
  • Best HTML5 structure for a layout where the title/header is outside the article tag
  • How to make SASS put relative paths in its output
  • back button function for phonegap windows phone 7
  • PHP multiple file uploads
  • Best practice to eliminate magic numbers within a member function
  • How to plot large time series (thousands of administration times/doses of a medication)?
  • Android cannot disable cut copy paste
  • Calculate time difference in hh:mm:ss with simple javascript/jquery
  • Tell Git to stop prompting me for conflicts when none really exist?
  • Elasticsearch script query involving root and nested values
  • Why use database factory in asp.net mvc?
  • How do I configure context broker accept post requests from my remote sensor?
  • How can I sort a a table with VBA with given text condition?
  • Jquery UI tool tip close icon
  • Alert pop up with LWUIT
  • Seeking advice on Jetty HttpClient Hang
  • Control modification in presentation layer
  • Display issues when we change from one jquery mobile page to another in firefox
  • Illegal mix of collations for operation for date/time comparison
  • Excel - Autoshape get it's name from cell (value)
  • Check if a string to interpolate provides expected placeholders
  • Javascript Callbacks with Object constructor
  • Google cloud sdk not working when python points python3
  • RestKit - RKRequestDelegate does not exist
  • Traverse Array and Display in markup
  • using HTMLImports.whenReady not working in chrome
  • How can I remove ASP.NET Designer.cs files?
  • python draw pie shapes with colour filled
  • Is there any way to bind data to data.frame by some index?
  • How can i traverse a binary tree from right to left in java?
  • How to Embed XSL into XML
  • Android Heatmap on canvas or ImageView