The hidden corners of Passenger

There are a few technical achievements in Passenger that we haven’t actively marketed. But we’d like the community to be aware of them, so we’ve written this blog post. :)

Unix domain sockets

Not too long ago, Thin announced support for Unix domain sockets. This gave Thin an incredible speed boost. Switchpipe soon followed, with alpha support for Unix domain sockets.

It has always surprised me that the Ruby/Rails web containers didn’t support Unix domain sockets until early 2008. Unix domain sockets aren’t exactly rocket science or exotic: the X Window System has used them for client-server communication on localhost for as long as I can remember. Database systems such as MySQL prefer to use Unix domain sockets on localhost as well. It’s also well-known that Unix domain sockets are faster than TCP sockets.

There’s one down side to Unix domain sockets though: you have to remove them. Usually, server processes remove them during exit. But if the system crashes, or if those processes crash, then the socket files are never removed, and the system administrator will have to do that manually. Ouch, maintenance overhead.

Passenger uses Unix sockets extensively, and has done so since the first release. But there’s one difference compared to Thin and Switchpipe: Passenger uses Unix sockets in the abstract namespace (as opposed to on the filesystem) whenever possible. Abstract namespace Unix sockets have filenames, just like regular Unix sockets, but they do not appear as files on the filesystem. This means that after a reboot, or if Apache crashes, no stale files will be left on the filesystem. This way, the system administrator doesn’t have to manually remove stale files if something went wrong.

Passenger strives for a concept that we call “zero maintenance”. We believe that software should Just Work(tm), and system maintenance overhead should be as low as possible. The system administrator shouldn’t have to worry about stuff like stale files, if he doesn’t have to. Ideally, the system administrator should be able to forget that he ever installed Passenger at all. The usage of abstract namespace Unix sockets is one of the mechanisms that we use to achieve that goal.

PID files (or the lack thereof)

Mongrel and Thin write so-called PID files to the filesystem. PID files contain the PIDs of background processes, and are used for shutting down those processes. But if the system crashes, or if those background processes crash, then the PID files will never be removed, and they become stale PID files. Early Mongrel versions refuse to start if there are stale PID files, forcing the system administrator to remove them manually. Passenger on the other hand doesn’t use PID files at all. If one shuts down Apache, then all Rails processes are shut down as well.

So what happens if Apache crashes? The Rails processes will exit as well. We use so-called “owner pipes” in Passenger, pipes that are shared between Apache and the Rails processes. Owner pipes are essentially a mechanism for reference counting processes. If Apache crashes, then the owner pipe is automatically closed. The Rails processes will detect this, and will shut down gracefully.

3 Comments »

  1. macournoyer said,

    April 27, 2008 @ 3:00 am

    While I agree it’s better to remove the unix socket file, multiple socket can listen on the same file, so if the file already exist no error will happen. That means, it’s not required to remove the file if the process crashed.

    Also Thin and Mongrel do remove stale pid files on start.

  2. Hongli said,

    April 27, 2008 @ 12:38 pm

    While I agree it’s better to remove the unix socket file, multiple socket can listen on the same file, so if the file already exist no error will happen. That means, it’s not required to remove the file if the process crashed.

    Is that really so?

    [hongli@hoshino ~]$ irb
    >> require 'socket'
    => true
    >> s1 = UNIXServer.new('foo.sock')
    => #<UNIXServer:foo.sock>
    >> s1.close
    => nil
    >> s2 = UNIXServer.new('foo.sock')
    Errno::EADDRINUSE: Address already in use - foo.sock
            from (irb):4:in `initialize'
            from (irb):4:in `new'
            from (irb):4
            from :0
    >> 
  3. macournoyer said,

    April 27, 2008 @ 3:42 pm

    Indead, I was wrong. I was under that impression because EventMachine deletes the file before binding to it. My point is that those 2 problems have been solved already. Although your solutions are more elegant.

RSS feed for comments on this post · TrackBack URI

Leave a Comment