On Foreman and Procfiles
Over the last few years I've amateurishly covered the entire stack from design to server administration, and on that tirade I've managed to break many rules.
Premature optimization? Check. Refactoring without reason? Check. Overengineering? Check.
I'm obsessive-compulsive about a few things. For example, I always fold chip bags into little squares before throwing them away. But that has nothing to do with anything. I'm a very detail-oriented person, but to a fault. If I find something interesting about a particular process, for instance, I will spend exorbitant amounts of time learning its ins and outs. Wasteful? That's a fair assumption.
But I'll spare you the rest of the details and talk about my find of the day, the Foreman gem and the Procfile
.
But don't you program in Python?
Shut your face, that mentality is so yesterday. I will prefer the Python implementation of a program as opposed to that of its rivals if and only if it is a more elegant solution. SASS and Compass proved that to me. Anybody remember CleverCSS? Yeah, thought so. Practicality beats purity.
Alright, class is in session. Let me flip this around and show you my Procfile
first, then explain what happens inside of it:
compass: compass watch static
db: postgres -D /usr/local/var/postgres
redis: redis-server /usr/local/etc/redis.conf
web: python ranking/manage.py runserver
So what does it do? Instead of opening a tab in Terminal for each of those items or starting them as a daemon, it allows me to concatenate the operation into one simple command:
foreman start -f Procfile.dev
Why .dev
? In my case, the sans-extension Procfile
in my project is for Heroku with production-only commands. If you run foreman
without the argument, it'll look for Procfile
by default. After you run that command you'll be greeted by this lovely sight:
14:14:37 compass.1 | started with pid 3115
14:14:37 db.1 | started with pid 3116
14:14:37 redis.1 | started with pid 3117
14:14:37 web.1 | started with pid 3118
Like what you see? Great! If you've gotten this far, you should've already installed the Foreman gem by now and created a Procfile. Now, there are a few gotchas when working with your services in Foreman, especially if you're using Homebrew, Redis and PostgreSQL:
- Foreman doesn't like daemons. If you throw a command into your
Procfile
that dameonizes the process, Foreman will start the process only to shut down entirely because it disappeared like it was supposed to. - To that point, test the commands that Homebrew gives you when you run
brew info <formula>
and see if it daemonizes. Here's a freebie: the PostgreSQL command that Homebrew gives you:pg_ctl -D /usr/local/var/postgres -l /usr/local/var/postgres/server.log start
WILL daemonize it. You're going to want the command posted above instead. - If your program logs to
STDOUT
it'll all be aggregated. But if you've ever runredis-server
through Homebrew, it's VERBOSE. To regain your sanity, go into/usr/local/etc/redis.conf
and change theloglevel
tonotice
orwarning
.
On a slightly related note, I love Homebrew. I just hate the way it instructs you to start processes. It's shit, especially if you're coming from a Linux development environment where upstart
lives to massage your feet and feed you grapes. Do yourself a favor and grab this script, throw it in your Homebrew's bin/
and profit using brew services start <formula>
, even if you don't use Foreman in the end.
If you do a quick search on Foreman, you'll rightfully see a slew of Ruby-centric articles. However, the amazing thing about this gem is that all it does is manage processes, so you can throw anything in there, no matter what language you happen to be programming in. Over the weekend I've been working on moving a wiki of ours to PHPFog, for my local install I've thrown php-fpm
, nginx
and mysql
in a Procfile
and it all Just Works™. No more struggling to remember commands. No more forgetting to shut processes off.
There are lots of great things that people have been doing with Procfiles
, automatically running tests after saving files in Django or exporting it to upstart
if you're on Linux are just two examples.
So for once my obsessiveness has rewarded me with a streamlined development workflow, and I hope it'll do the same for you!