Foreman: Separate, development-only Procfile

Created on 1 May 2013  ·  9Comments  ·  Source: ddollar/foreman

We're using Foreman to start our node.js app in development. We've encountered a recurring problem: Developers accidentally check in changes they made to the Procfile for development purposes, which results in the wrong processes starting in Heroku.

Specifically, our devs would like to start their MongoDB and Redis processes with the rest of the app when developing, so they modify the Procfile. If they're in a hurry or forgetful, the Procfile changes end up in production.

To work around this issue, I've implemented a number of bin/ scripts as suggested by this comment to conditionally start processes only if $NODE_ENV=development. This does help protect the Procfile from accidental changes, and it does help us keep the right things running in production, but our production Heroku app dashboard now has "memento" of a Redis and MongoDB process that were started then immediately exited.

heroku-dashboard-with-non-running-mementos3

I've asked the Heroku team if they could try to start their Celadon Cedar stack with something other than the default Procfile. For example, if they could try to start with Procfile-heroku first, and then fall back to Procfile if that file is not found. They suggested that I file this as an issue with Foreman. I don't understand how changing Foreman will help with this issue, however, I'm writing it up here and perhaps someone can give me some insight.

Most helpful comment

I wish this could be revisited—the fact that both Heroku and Foreman use a file called Procfile that I need to have different things in is really annoying. I use Foreman to start all the service dependencies for an app—like Redis and the Resque dashboard—in development, but do not want processes for many of them in production on Heroku.

Did Procfile originate with Foreman in the first place or was it a pre-existing standard for listing processes from an earlier tool? In an ideal world for me, Procfile would actually be a Yaml file with top-level keys for environments just like the Rails config/database.yml database configuration file, because then you could do things like this:

production: &production
  rails: bundle exec rails server
  resque: bundle exec rails resque:work QUEUE=*
development: &development
  <<: *production
  redis: redis-server
  resque_dashboard: bundle exec resque-web --foreground --no-launch
test: *development

All 9 comments

I use Procfile for production (heroku), and Procfile-dev for local development.

I just start it like:

foreman start -f Procfile-dev

@ambethia In my experience, humans sometimes forget things. Sometimes they're lazy. Sometimes they just don't know the "right" way to do something.

As I proposed to the Heroku devs, having the startup script use a non-default Procfile for production will help in those situations when developers forget, are lazy, or just don't understand.

There are a few advantages to having a non-default Procfile used for Heroku:

  1. The production Procfile will be clearly labeled, i.e. Procfile-heroku, instead of just Procfile
  2. The default Procfile can be put into .gitignore to prevent accidental checkins by developers.
  3. Startup requires less typing for developers who will can just use foreman start. The startup script can use the long form foreman start -f Procfile-heroku

You're right in that using multiple Procfiles can easily lead to confusion. There are two reasons I don't want to do this:

  1. Dev/prod Parity: Dev and prod should be as close to each other as possible to prevent the introduction of discrepancies.
  2. We try incredibly hard to avoid requiring Heroku-specific changes to your code in order for it to run on the Heroku platform.

I use binscripts to solve this problem. For example, I want to run nodemon, an auto-reloading web-server in development, but not in production. You can see an example of this in another of my projects, anvil:

You can see that bin/web has some conditional logic based on whether or not NODE_ENV is set to production. I believe that this is a cleaner and easier approach to this problem.

@ddollar It sounds like you're recommending that we remove our Redis and MongoDb process startups from Foreman, since in production we don't host these on Heroku, and therefore they will never be part of the Heroku startup process. Is this correct?

That would be up to personal preference. I don't personally put stuff like that in my Procfile, but I know that others do. I generally just have machine-wide Couch, Mongo, Redis, etc that I use locally.

The way I do this is to use a separate Procfile-local that runs all services that are local-only, like my static files server, and also invokes foreman (recursively) to execute the regular Procfile. All your logs will have an extra level of nesting, but other than that, it works fine.

@ddollar Just came across this. Another thing you can do is to have the separate Procfile (as mentioned above) and then setup bash aliases to start foreman locally using the local file, i.e.:

# in .bash_profile or similar
alias fman='foreman start -f Procfile.local'

^ very nice. for some reason using the foreman -f command this way doesn't work for me

I used copied the contents of my Procfile.local to Procfile and running

foreman start

works
but using

foreman start -f Procfile.local

I get some sort of rails exception just trying to run rails s as the server.

foreman start --procfile=Procfile.local
19:15:29 server.1  | started with pid 71750
19:15:31 server.1  | syck has been removed, psych is used instead
19:15:31 server.1  | Error: Command not recognized
19:15:31 server.1  | Usage: rails COMMAND [ARGS]
19:15:31 server.1  | 
19:15:31 server.1  | The most common rails commands are:
19:15:31 server.1  |  generate    Generate new code (short-cut alias: "g")
19:15:31 server.1  |  console     Start the Rails console (short-cut alias: "c")
19:15:31 server.1  |  server      Start the Rails server (short-cut alias: "s")
19:15:31 server.1  |  dbconsole   Start a console for the database specified in config/database.yml
19:15:31 server.1  |              (short-cut alias: "db")
19:15:31 server.1  |  new         Create a new Rails application. "rails new my_app" creates a
19:15:31 server.1  |              new application called MyApp in "./my_app"
19:15:31 server.1  | 
19:15:31 server.1  | In addition to those, there are:
19:15:31 server.1  |  application  Generate the Rails application code
19:15:31 server.1  |  destroy      Undo code generated with "generate" (short-cut alias: "d")
19:15:31 server.1  |  benchmarker  See how fast a piece of code runs
19:15:31 server.1  |  profiler     Get profile information from a piece of code
19:15:31 server.1  |  plugin       Install a plugin
19:15:31 server.1  |  runner       Run a piece of code in the application environment (short-cut alias: "r")
19:15:31 server.1  | 
19:15:31 server.1  | All commands can be run with -h (or --help) for more information.
19:15:31 server.1  | process terminated
19:15:31 system    | sending SIGTERM to all processes

I wish this could be revisited—the fact that both Heroku and Foreman use a file called Procfile that I need to have different things in is really annoying. I use Foreman to start all the service dependencies for an app—like Redis and the Resque dashboard—in development, but do not want processes for many of them in production on Heroku.

Did Procfile originate with Foreman in the first place or was it a pre-existing standard for listing processes from an earlier tool? In an ideal world for me, Procfile would actually be a Yaml file with top-level keys for environments just like the Rails config/database.yml database configuration file, because then you could do things like this:

production: &production
  rails: bundle exec rails server
  resque: bundle exec rails resque:work QUEUE=*
development: &development
  <<: *production
  redis: redis-server
  resque_dashboard: bundle exec resque-web --foreground --no-launch
test: *development
Was this page helpful?
0 / 5 - 0 ratings

Related issues

jwaldrip picture jwaldrip  ·  17Comments

maxehmookau picture maxehmookau  ·  5Comments

jasonivers picture jasonivers  ·  8Comments

dunkstewart picture dunkstewart  ·  12Comments

kurtnovack picture kurtnovack  ·  5Comments