foreman development vs production (rails) - ruby-on-rails

what is the "foreman way" for behaving differently in production vs
development? That is we want foreman start to start up a bunch of
stuff in dev, however in heroku production we don't need it to start
(for example) solr.

I follow the convention;
Procfile defines all processes
.foreman set specific foreman variables
Development:
.env sets environment variables for each developer
.env.example sets defaults for development
foreman start starts all processes
Production:
heroku config sets environment variables
heroku ps:scale turns on or off whichever processes are needed for production
Here's an example from a project.
Procfile:
web: bundle exec unicorn_rails -p $PORT -c ./config/unicorn.rb
worker: bundle exec rake jobs:work
search: bundle exec rake sunspot:solr:run
.env.example:
# default S3 bucket
S3_KEY=keykeykeykeykeykey
S3_SECRET=secretsecretsecret
S3_BUCKET=myapp-development
.env
# developer's private S3 bucket
S3_KEY=mememememememememe
S3_SECRET=mysecretmysecret
S3_BUCKET=myapp-development
.foreman:
# development port is 3000
port: 3000

Foreman takes arguments to use a different file (-d) and arguments to specify what to run. It also supports a .foreman file that allows those args to become default. See http://ddollar.github.com/foreman/ for more info

I've used environment-specific Procfiles before, which is pretty simple and works fine.
Basically you have Procfile.development, Procfile.production, etc. In each you can customize the procs you want to start, then run them via foreman like so:
foreman start -f Procfile.development
Another approach is to reference scripts in your Procfile, and within each script start up the appropriate process based on the environment. The creator of Foreman does this and has an example from his Anvil project your reference.

Our solution was to use a separate job type in our Procfile for dev vs. production. It is not the most DRY method, but it works...
sidekiq: bundle exec sidekiq
sidekiq-prod: bundle exec sidekiq -e production
Then we run foreman specifying the prod job on the production system:
foreman start -c sidekiq-prod=4

Related

Automate a rake task to run on boot on heroku?

Suppose there's a task
rake startupscript
that should run whenever the app boots, how can we automate that on heroku?
I know there's a heroku scheduler but that will run the task every 10 minutes instead of just once at boot. I also know of the Procfile and believe this can be a solution, although I do not yet know how to implement (and probably more importantly, I don't want to risk breaking anything else that can be configured via a Procfile, e.g. webserver etc). A lot of the Procfile docs focus on using it to alter web servers rather than app level rake tasks.
How can a rake task be made to run at boot?
You can add something like this to Procfile before you start your application services
# Run pre-release-tasks here
release: bundle exec rails db:migrate
# Then run your application
web: bundle exec puma -t 5:5 -p ${PORT:-3000} -e ${RACK_ENV:-development}
Anything tagged as release will run before the startup script runs
https://devcenter.heroku.com/articles/release-phase

Foreman conditional running processes

I have a foreman app with a Procfile like this
web: bundle exec rails s
custom_process: bundle exec rake custom:process
faking_custom_process: bundle exec rake custom:faking_process
And I want to run custom_process or faking custom_process depends on my needs:
foreman start # run web & custom_process
FAKING_PROCESS # run web & faking_custom_process
Yes, I know about ability of running like that foreman start -c faking_custom_process=0, but this is more difficult than I expect, right?
There's no option in foreman to just skip a process. I think you'd need to extend your start invocation to do something different too if you want to run the other processes. Otherwise you're just telling it to run zero copies of faking_custom_process and nothing else:
foreman start -m web=1,custom_process=1,faking_custom_process=0
or for the faking version:
foreman start -m web=1,custom_process=0,faking_custom_process=1
You could of course script that so you've got two scripts running those different versions.
An alternative would be to switch faking on or off using a variable in the environment (I'm not convinced it's any easier but it's an alternative):
web: bundle exec rails d
custom_process: PROCESS=$FAKING"process" && bundle exec rake custom:$PROCESS
A normal foreman start will just run bundle exec rake custom:process.
For the faking equivalent you can do:
export FAKING="faking_"
which will mean that from then on foreman start it will call bundle exec rake custom:faking_process instead.
You can return to the normal process by clearing the FAKING variable with:
export FAKING=
You could of course encapsulate that into a shell script too.
You can use .profile to store default options for foreman start:
concurrency: web=1,custom_process=1,faking_custom_process=0
or using shortcut:
concurrency: all=1,faking_custom_process=0
And then you override this default option to switch to fake process:
foreman start -c all=1,custom_process=0
See: http://ddollar.github.io/foreman/#DEFAULT-OPTIONS

Cannot set staging environment for Rails application

I'm deploying Rails application to server. I can easily accomplish everything if I need only production. But I need staging as well.
I launch my unicorn server with the following command:
bundle exec /home/deployer/apps/myapp/shared/bundle/ruby/2.0.0/bin/unicorn_rails \
-D -c /home/deployer/apps/myapp/shared/config/unicorn.config.rb -E staging
But regardless of my command, the server launches application with production environment.
Is there another place in my application where I should specify environment to be staging?
Thanks!
Set the environment variable RAILS_ENV=staging before you run the command. You can do it on the same line even (in Bash):
$ RAILS_ENV=staging bundle exec unicorn...
You would have to have the environment set up in multiple files such as config/environments/ and config/database.yml.

ruby run code in separate process from webapp

I have a file with worker class (worker.rb) and I need to instantiate it in separate process from rails application after getting the command. I'm currently working on windows os.
So how to do that?
P.S. Will that code work in unix/linux env?
Check out foreman
https://github.com/ddollar/foreman
You can put a Procfile in your Rails root with instructions for starting both your rails server and your worker and then run foreman start to launch them. Here is a sample Procfile:
web: bundle exec unicorn_rails -p 8088
scheduler: bundle exec rake resque:scheduler
worker: bundle exec rake resque:work
Foreman is compatible with both Windows and Linux, so it should work regardless of your platform.

Heroku/ruby on rails... how can I figure out if I'm running as a worker or a web

I have an app on (ruby/rails) heroku. It's running 1 web and 1 worker (for example)
I want to be able to tell what "type" of dyno the app is running under.
I suspect it's a simple thing to tell, but I can't see anything that tells me how to tell.
I don't know if there's a more elegant way to do this, but you can set an environment variable in your Procfile:
web: bundle exec ... PROC_TYPE=web
worker: bundle exec ... PROC_TYPE=worker
Then in your rails code, you can check ENV['PROC_TYPE']
EDIT: more detailed Procfile example, typical for a rails app:
web: bundle exec rails server -p $PORT PROC_TYPE=web
worker: bundle exec rake jobs:work PROC_TYPE=worker

Resources