|Correct shutdown Yesod||Dmitriy Nikitinskiy||7/21/11 1:05 AM|
How to correct shutdown Yesod application?
Calling in route handler liftIO (exitSuccess) just raises Internal Server erorr and server continue working.
I found liftIO (raiseSignal sigTERM) that terminates process itself, but this method is not crossplatform and I not sure about correct releasing used resources by such method.
Is any correct method gracefully shutdown Yesod application?
|Re: [Yesod] Correct shutdown Yesod||Michael Snoyman||7/21/11 5:14 AM|
It's funny you should ask this, Greg and I were just discussing signal
handling ourselves. The answer is that shutdown will depend on which
WAI handler you're using. Let's assume you're using Warp (since I
think everyone is at this point). Warp runs in an infinite loop
accepting connections and handing them off to new threads. Warp also
ignores all exceptions thrown from the application, to make sure that
one bad request won't take down the whole server. That seems to be why
exitSuccess causes an internal server error.
So the question is how do we signal Warp to shutdown. One possibility
We could then use this IORef to handle signals (as is necessary on Heroku).
Any thoughts on this?
2011/7/21 Dmitriy Nikitinskiy <nikit...@gmail.com>:
|Re: [Yesod] Correct shutdown Yesod||Greg Weber||7/21/11 6:46 AM|
If someone that knew more about signal handling in GHC could make suggestions, that would be helpful :).
I do see there is support for installing signal handlers in GHC: http://hackage.haskell.org/trac/ghc/wiki/Commentary/Rts/Signals
Why do we need an IORef *passed* to Warp? It seems like Warp should be able to handle this on its own.
I am wondering what Dmitry's use case is, because it doesn't seem like a frequent case that one would want to shutdown the application from inside it! It seems more appropriate to send a signal from the outside, at which point Warp will stop accepting new connections and will return from its loop. Could it return thread ids to wait on or is there too much overhead associated with that?
One ideal usage case for Warp and Signal handlers would be to send a signal that would allow one to switch to a new version of the application with zero downtime. But there might be other approaches to achieving this that work better.
|Re: [Yesod] Correct shutdown Yesod||Dmitriy Nikitinskiy||7/21/11 6:51 AM|
It's ok for me, using IORef running flag.
Or as variant maybe add ResponseControl to Response data to controlling Wai handler (not only running-flag)?
|Re: [Yesod] Correct shutdown Yesod||Michael Snoyman||7/21/11 7:27 AM|
On Thu, Jul 21, 2011 at 4:46 PM, Greg Weber <gr...@gregweber.info> wrote:
Warp *could* handle this on its own, but:
1) Signals only exist on POSIX systems.
> I am wondering what Dmitry's use case is, because it doesn't seem like a
I can imagine having a "shutdown" button on an admin panel. Especially
What do you mean by return thread ids?
> One ideal usage case for Warp and Signal handlers would be to send a signal
I think the approach just mentioned would achieve this: sending the
|Re: [Yesod] Correct shutdown Yesod||Michael Snoyman||7/21/11 7:28 AM|
On Thu, Jul 21, 2011 at 4:51 PM, Dmitriy Nikitinskiy
It's possible to do this, but I'd rather not. I don't want to start
|Re: [Yesod] Correct shutdown Yesod||Greg Weber||7/21/11 7:46 AM|
By thread ids I mean the thread id for each request that is still on-going.
This shutdown scenario still wouldn't be true zero downtime- the new application need to be loaded into memory before the old begins to shutdown. There is a server for Ruby apps called Unicorn with true zero downtime- it accomplishes this by having several worker forks that get replaced by new worker forks of the new application. Compiling Warp directly into the application doesn't allow for this approach. It should be possible to use a proxy that would start sending requests to the new application while the old is shutting down. Of course there is an issue of memory consumption under such an approach.
I am still confused about the recommended approach- someone has to catch signals- is Yesod going to do that by default now?
|Re: [Yesod] Correct shutdown Yesod||Michael Snoyman||7/21/11 7:53 AM|
On Thu, Jul 21, 2011 at 5:46 PM, Greg Weber <gr...@gregweber.info> wrote:
> By thread ids I mean the thread id for each request that is still on-going.
I think we should defer true zero downtime to a load balancer outside
> I am still confused about the recommended approach- someone has to catch
The idea is that we'd set up a signal handler before calling Warp. In
flag <- newIORef True
Warp will continue running until that flag is set to False, which will
|Re: [Yesod] Correct shutdown Yesod||Greg Weber||7/21/11 8:09 AM|
ok, that looks good. What I was getting at with thread ids is that if they are returned from Warp then you could actually wait for them rather than doing an opaque hack like sleeping. The other possibility would be for Warp to write back to the IORef when all of its threads are completed (this in itself would require creating a new thread for the current Warp call to return, or at least to return an action that waits on existing threads). But I know little about the Warp implementation to know if that is a minor or major change.
|Re: [Yesod] Correct shutdown Yesod||Felipe Lessa||7/21/11 8:29 AM|
On Thu, Jul 21, 2011 at 11:53 AM, Michael Snoyman <mic...@snoyman.com> wrote:
There could also be an exception
data StopWarp = StopWarp deriving (Show, Typeable)
that could be thrown by the application. This would be only exception
However, I don't know if it would be possible to do away with the flag
|Re: [Yesod] Correct shutdown Yesod||Michael Snoyman||7/21/11 8:49 AM|
Interesting idea, it could be a very good approach. The only possible
 Exceptional exceptions.
|Re: [Yesod] Correct shutdown Yesod||Michael Snoyman||7/21/11 10:50 PM|
OK, scratch everything I said before, it was a bad approach. An IORef