Recently I’ve been working on a project combining an HTTP server and a WebSockets server. Traffic from both HTTP and WebSocket clients can affect server state and consequently an HTTP client can affect a WebSockets client and vice-versa. We are prototyping this in JRuby as a single
.war file using warble. The HTTP server is using Winstone, and the WebSockets server is using em-websocket. Since we are also prototyping clients of both stripes, and testing overall behavior with Cucumber, it is crucial that the server stops and restarts quickly as we test. However, getting a simple “stop” message through was a bit like going through an obstacle course.
Generally speaking, when running Winstone from the command line, it expects a straightforward Ctrl-C (or SIG-INT) to bring it to a close. In fact it traps this signal and begins its shutdown routine. In our case, though, the WebSockets server we launched alongside our Sinatra web application decided it needed to do the same thing. So the Websockets code trapped the SIG-INT, shut down eventmachine, and just assumed that everything would sort itself out. Not so.
That was fairly simple to fix. We just stopped trapping the SIG-INT, and then Winstone shut down properly from the command line. At that point we thought we were in the clear. Again we were mistaken. Later on we realized that any unexpected Exception in our Websockets code would stop the Websockets server or corrupt its state, but let Winstone keep going with the HTTP sever. For our tests, we would prefer any unexpected Exception to trigger a fail of the scenario in Cucumber and shut down the entire server. So we tried raising the error to Winstone rather than swallowing it at the WebSockets level, but it ignored the error. We also tried raising an Interrupt exception – no dice. It looked like Winstone really didn’t want to be stopped from the inside. In frustration, and wanting to get on with our tests, we decided to go for the less graceful approach –
java.lang.System.shutdown. Ugly, but very effective.
A few days later, with the bitter taste of an abrupt and messy solution still lingering, I decided to dig into the Winstone documentation and see if there was a more graceful way to shut down Winstone from inside our app code. I didn’t find one, but I did find a perfectly workable solution to use from the “outside”: the
controlPort. All I had to do was open up a TCP connection to localhost in our code when an error happened, send down one bit, and – voila! It just goes to show that every now and then it pays to go look at the documentation before you go traipsing through the code. Now we have a server that restarts gracefully on error, and em-websocket and Winstone don’t get in the way.