Skip to content

Instantly share code, notes, and snippets.

@czottmann
Created June 15, 2011 13:43
Show Gist options
  • Star 56 You must be signed in to star a gist
  • Fork 17 You must be signed in to fork a gist
  • Save czottmann/1027117 to your computer and use it in GitHub Desktop.
Save czottmann/1027117 to your computer and use it in GitHub Desktop.
Example of a Foreman/Capistrano/upstart setup

Example of a Foreman/Capistrano/upstart setup

I need to jot down my Foreman-based web app setup real quick lest I forget.

When I build a Rails app (any web app, actually), it's not just the app itself anymore. There also are background jobs to be taken care of -- started, stopped, restarted. Usually these are required to run in production on a remote box, too, so I use Foreman to run those jobs. Foreman uses a Procfile to learn about said jobs, gives me a dead-simple way to start and stop them, and provides me with color-coded output when they run. It's a great timesaver.

Then, when I deploy my app to a remote machine, I use Foreman's ability to export upstart (or inittab) configurations. For that, I have custom tasks in my Capistrano-based config/deploy.rb file. Those halt the current jobs on the remote machine, trigger Foreman to write out new configurations for upstart and re-start the jobs. (Please note: Foreman needs to be installed on the remote box as well.)

Since it took me a while to get this setup working, I figured I'd share it real quick.

My examples come from a Rails-based environment, but I tried to make them app-agnostic as possible.

This here "article" is basically a bare-bone, stripped down version of Tim Riley's "Run Your Own Piece of Heroku with Foreman".

Assumptions

  • The Foreman gem is installed both on the local dev machine and the remote box
  • Deployment is done using Capistrano
  • The remote machine is running Ubuntu
  • The remote machine has upstart installed
### Foreman-related snippet of `config/deploy.rb` below.
### Rest of the file omitted!
namespace :foreman do
desc "Export the Procfile to Ubuntu's upstart scripts"
task :export, :roles => :app do
run "cd /var/my-ossum-app && sudo bundle exec foreman export upstart /etc/init -a my-ossum-app -u ossum-user -l /var/my-ossum-app/log"
end
desc "Start the application services"
task :start, :roles => :app do
sudo "start my-ossum-app"
end
desc "Stop the application services"
task :stop, :roles => :app do
sudo "stop my-ossum-app"
end
desc "Restart the application services"
task :restart, :roles => :app do
run "sudo start my-ossum-app || sudo restart my-ossum-app"
end
end
after "deploy:update", "foreman:export"
after "deploy:update", "foreman:restart"
worker: QUEUE=* bundle exec rake environment resque:work
scheduler: bundle exec rake environment resque:scheduler
@stationkeeping
Copy link

How are you able to use $ sudo bundle exec foreman? Did you install rbenv for the root user?

@heygambo
Copy link

You might want to try #{sudo} instead of sudo

@tinynumbers
Copy link

@thisisbrians
Copy link

rvmsudo worked for me: https://rvm.io/integration/sudo

@sjchristi
Copy link

ran into a similar issue, using rbenv. Ended up using a solution I found on the web in a railscast comments.

in deploy.rb:

def rbenv(command)
  run "#{command}", :pty => true do |ch, stream, data|
    if data =~ /\[sudo\].password.for/
      ch.send_data(Capistrano::CLI.password_prompt("sudo password: ") + "\n")
    else
      Capistrano::Configuration.default_io_proc.call(ch, stream, data)
    end
  end
end

then a slight change to the task above:

  desc "Export the Procfile to Ubuntu's upstart scripts"
  task :export, :roles => :app do
    rbenv "cd #{current_path} && rbenv sudo bundle exec foreman export upstart /etc/init --procfile=Procfile.production -a #{application} -u #{user} -l #{current_path}/log"
  end

thank you for the recipe.

sam

@jameskerr
Copy link

Very useful. I am digging it. I believe I will borrow this set-up for my app. Tried using God to monitor workers, but didn't like it very much. Foreman + Upstart + Capistrano looks like a great combo.

@jobwat
Copy link

jobwat commented Jul 9, 2014

I'm using this solution and I was getting an error message at each restart:

*** [err :: staging.my-ossum-app.com] start: Job is already running: my-ossum-app

Which makes sense but damage the feedback (it should just be a warning)
So I'm now striping out from the error output this 'Job is already running' message, but it's ugly:

run "{ sudo start my-ossum-app 2>&1 1>&3 | grep -v 'Job is already running' 1>&2; } 3>&1 || sudo restart my-ossum-app"

If anyone have a better restart mechanism non-error-verbose, I'm keen :)

@cbilgili
Copy link

More revised version for Capistrano >= v3.0

namespace :foreman do
  desc "Export the Procfile to Ubuntu's upstart scripts"
  task :export do
    on roles(:app) do
      within current_path do
        execute :rbenv, :exec, "bundle exec foreman export upstart /etc/init --procfile=./Procfile -a #{fetch(:application)} -u #{fetch(:user)} -l #{current_path}/log"
      end
    end

  end

  desc "Start the application services"
  task :start do
    on roles(:app) do
      within current_path do
        execute :rbenv, :exec, "foreman start #{fetch(:application)}"
      end
    end

  end

  desc "Stop the application services"
  task :stop do
    on roles(:app) do
      within current_path do
        execute :rbenv, :exec, "foreman stop #{fetch(:application)}"
      end
    end
  end

  desc "Restart the application services"
  task :restart do
    on roles(:app) do
      within current_path do
        execute :rbenv, :exec, "foreman start #{fetch(:application)} || foreman restart #{fetch(:application)}"
      end
    end
  end
end

after "deploy:publishing", "foreman:export"
after "deploy:publishing", "foreman:restart"

@candidosales
Copy link

Thanks!! 👍

@mihaibb
Copy link

mihaibb commented Jun 30, 2016

I'm looking to update this script so I can export the foreman configuration different on specific machines.
For example I want the worker service to be only exported on servers with role worker.
The same for web and db.
Any ideas ?

@GraniteConsultingReviews

I update my script but it is not working.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment