-
Notifications
You must be signed in to change notification settings - Fork 582
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Terminable Middleware #147
Comments
This isn't really a go problem. We have go routines. PHP doesn't. |
After the response is over, all currently-running goroutines will get shut down due to current implementation of negroni. Terminable middleware happen outside of request-response cycle. |
@pjebs I was looking for how that works. Can you show me which file that happens in? I use websockets with negroni and hijack the connection and it keeps on running so I'm interested in how that works. |
I was asking how the handler shuts down all the go routines that were spawned while it was running. I didn't know you could so that without using channels. Would love to learn more. |
If it's not in the negroni code, it's because In Go, all goroutines will get shut down automatically if the code that called it returns. That's the default behaviour with go. You can work around it by either preventing the caller from returning in the first place (i.e. using waitgroups etc) but that isn't a solution for negroni. What negroni needs to do is itself call the middleware's |
@pjebs can you clarify what you mean by
I'm not sure I see the difference. |
@pjebs I'm sorry, but can you show me in the code where this is the case? I don't believe it works that way unless you specifically use something like "context" or write your go-routines to specifically listen to a channel. The only time this would happen is if the runtime exited, and in a server this would basically never happen unless you're shutting down or have crashed. |
@yanfali To test my claim: Add this to any negroni handler:
Add this to inside a negroni handler. According to my assertion, the handler is kept alive for 5 seconds. Whilst it is alive, the goroutine will keep logging for 5 seconds. After the handler returns after 5 seconds, the goroutine is shut down by net/http's webserver automatically. |
@jszwedko I'll create a proof of concept PR soon to explain. |
I'll give it a try. I'm wondering if your spammy go routine is being On Sat, Sep 24, 2016, 17:54 pjebs [email protected] wrote:
|
This seems relevant golang/go#10958 On Sat, Sep 24, 2016, 18:02 Yan-Fa Li [email protected] wrote:
|
I just ran this for over 5 minutes, it's still going package main
import (
"log"
"net/http"
"time"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
//Inside a handler
go func() {
for {
log.Println(time.Now())
time.Sleep(time.Millisecond * 100)
}
}()
time.Sleep(5 * time.Second)
})
log.Fatal(http.ListenAndServe(":8080", nil))
} I guess you're deadlocking the GC or the Scheduler because you're running it in a tight loop. |
This was on a linux AMD64 system with 16 real cores, 64G of RAM and 4.7 kernel. I have not tried this on windows or OSX. I used go 1.7.1 to compile this program. |
@yanfali I guess I learnt something. You proved me wrong! I'm now the one really confused. |
I was actually genuinely interested that you had discovered something I didn't know, so we both learned something. |
From here: https://www.golang-book.com/books/intro/10
This kind of thing when I first learnt Go is the source of my confusion. I'm really more confused now. Do you see that sample code? They put the The only way I can reconcile your discovery and the statement in that book (assuming it is true) is to assume it only applies to the |
@jszwedko With @yanfali 's proof, which I've tested, we don't need terminable middleware. I will close this issue soon. However, as per my concern in: #138 (comment), the recovery middleware should definitely be changed to:
go func() { being the change |
@pjebs ping - probably ok to close this now right? |
Added a pull request: #165 |
I definitely think this should be implemented for Negroni.
Terminable middleware allows you to add code that runs AFTER the response has been fully served.
There is a subtle but crucial difference to adding code after
next(rw, r)
.It is also related (vaguely) to an issue I highlighted here: #138 (comment) where in the the recovery middleware, if you were to add a custom error handler, the handler wastes time from client's perspective.
Further Reading:
https://laravel.com/docs/5.3/middleware#terminable-middleware
The text was updated successfully, but these errors were encountered: