Scenario: User submits something, I want to give an instantaneous response "ok received", so that the user can go on his way. Meanwhile, I need to spend 2-3 seconds to perform some computation on the new submission (e.g., generate thumbnails, add indices, inform admins). Users don't need to wait for the result, but I want the computation done asap.
My current solution is to launch a goroutine for heavy stuffs before returning response. I don't know whether this is the best practise. In my opinion, this is wasteful, because it should be cheaper to continue on the same thread instead of launching a new one. It also appears that when I perform gin.JSON(...), the result is sent already? even if there are more lines down the road?
Is it possible to first return the response and then continue in the same thread? Does gin support this already?
Comment From: nazwa
I would say a goroutine is the easiest way to do this. They are massively optimized and the overhead is tiny.
If you're worried about goroutine startup overhead, you could super easily implement a small job/worker pattern within your app and dispatch jobs through channels. This is still one of the best inspiration texts when it comes to workers (with examples) http://marcio.io/2015/07/handling-1-million-requests-per-minute-with-golang/
Alternatively, you could try manually closing the writer, that should close the connection.
Comment From: javierprovecho
@mingyuguo, I agree with @nazwa.
Either call a goroutine or use channels (careful with buffer lenght).
If you keep working on the same thread, middlewares who use c.Next()
should also use IsAborted()
. Not many do that, so some panic can emerge from that (using an aborted context).
Comment From: ica10888
go func() {
select {
case <-c.Request.Context().Done():
log.Infof("after returning response")
}
}()
time.Sleep(10 * time.Second)
log.Infof("returning response")
c.JSON(http.StatusOK, "returning response")
return
Use goroutine
and Context
in request may solve this problem.
returning response
after returning response
Comment From: twocs
Word of warning, gin will handle panics, but once you send the work to a go routine that doesn't handle the panic, a panic will cause a crash. This happens even if you access the context (as in the response by @ica10888). Therefore, to avoid terminating the process, either make sure a panic can never occur in the goroutine, or you might capture the panic.
go func() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered in f", r)
}
}()
select {
case <-c.Request.Context().Done():
log.Infof("after returning response")
}
}()
time.Sleep(10 * time.Second)
log.Infof("returning response")
c.JSON(http.StatusOK, "returning response")
return