Question description
Should we check for context done/cancel on every handler? For the case like client cancel the request, and the handler should cancel the ongoing operation (db query etc).
Possible to achieve with middleware, so that we don't keep repeating?
If you are doing a database query it would be good practice to pass the c.Context(), but I personally always set a timeout within the db adaptor instead. It's up to you 馃憤
@Fenny I get the idea, not sure how to implement it
To make the context cancel when the response is canceled by client?
func main() {
app := fiber.New()
app.Get("/", func(c *fiber.Ctx) error {
go func() {
select {
case <-c.Context().Done():
log.Println("done")
}
}()
// assume some heavy operation will take 2 seconds
// to make it cancelable
_ = heavyOperation(c.Context())
return c.SendString("Hello, World 馃憢!" + time.Now().Format(time.Kitchen))
})
log.Fatal(app.Listen(":3000"))
}
func heavyOperation(ctx context.Context) error {
deadline, _ := ctx.Deadline()
if deadline.Before(time.Now()) {
time.Sleep(2 * time.Second)
return nil
}
return nil
}
when i cancel the response half way, it doesn't print done. Not sure if i implement it correctly
The problem is that *fiber.Ctx is returned to the sync.Pool when you return from the handler. So c.Context().Done() becomes non-existent. It is better to handle the request in a separate thread while waiting for the context to be done.
type Data struct {
Data []int `json:"data"`
}
func main() {
app := fiber.New()
app.Get("/", func(ctx *fiber.Ctx) error {
c, cancel := context.WithTimeout(ctx.Context(), 50*time.Millisecond)
defer cancel()
res := Data{}
ch := make(chan Data)
go process(ch)
select {
case <-c.Done():
fmt.Printf("error: processing timeout\n")
break
case res = <-ch:
fmt.Printf("finished processing\n")
}
return ctx.JSON(res)
})
log.Fatal(app.Listen(":3000"))
}
func process(ch chan<- Data) {
fmt.Printf("processing started...\n")
time.Sleep(time.Duration(2 * time.Second)) // uncomment this
fmt.Printf("ended after 50ms\n")
a := []int{1, 2, 3, 4, 5, 6, 7, 8}
rand.Seed(time.Now().UnixNano())
rand.Shuffle(len(a), func(i, j int) { a[i], a[j] = a[j], a[i] })
ch <- Data{a}
}
Thanks for the example. If that is the case, then we can't extract it to a middleware i guess like timeout?
Because of ch <- Data{a}, it expects data from channel
I'm afraid that is not possible nor efficient with fasthttp sync.pool design
I guess the best alternative is limit response time with timeout middleware. Close it for now.