I have a few apps running rails 3 on ruby 1.9.2 and deployed on a Ubuntu 10.04 LTS machine using nginx + passenger. Now, I need to add a new app that runs on ruby 1.8.7 (REE) and Rails 2. I accomplished to do that with RVM, Passenger Standalone and a reverse proxy.
The problem is that, every time I have to restart the server (to install security updates for example), I have to start Passenger Standalone manually.
Is there a way to start it automatically? I was told to use Monit or God, but I couldn't be able to write a proper recipe that works with Passenger Standalone. I also had a few problems with God and RVM, so if you have a solution that doesn't use God, or if you know how to configure God/Rvm properly, it's even better.
Here is what I got working. Using Upstart (Ubuntu 10.04) to start the passenger daemon
My environment uses rvm with ruby 1.9.2 and apache and my rails app is deployed via capistrano
# Upstart: /etc/init/service_name.conf
description "start passenger stand-alone"
author "Me <me#myself.am>"
# Stanzas
#
# Stanzas control when and how a process is started and stopped
# See a list of stanzas here: http://upstart.ubuntu.com/wiki/Stanzas#respawn
# When to start the service
start on started mysql
# When to stop the service
stop on runlevel [016]
# Automatically restart process if crashed
respawn
# Essentially lets upstart know the process will detach itself to the background
expect fork
# Run before process
pre-start script
end script
# Start the process
script
cd /var/path/to/app/staging/current
sh HOME=/home/deploy /usr/local/rvm/gems/ruby-1.9.2-p136#appname/gems/passenger-3.0.7/bin/passenger start --user 'deploy' -p '5000' -a '127.0.0.1' -e 'production'
end script
and the apache config:
<VirtualHost *:80>
ServerName myapp.com
PassengerEnabled off
<Proxy *>
Order deny,allow
Allow from all
</Proxy>
ProxyPass / http://127.0.0.1:5000/
ProxyPassReverse / http://127.0.0.1:5000/
</VirtualHost>
Upstart doesn't set ENV['HOME'] which passenger relies on, so we have to pass that when executing the passenger command. Other than that its pretty straight forward.
A note for debugging: https://serverfault.com/questions/114052/logging-a-daemons-output-with-upstart (append something like >> /tmp/upstart.log 2>&1 to the second line in the script block)
Hope this helps.
I would suggest writing a shell script that can start this successfully, then use that in either a Monit or God recipe, if you're still willing to use them, or an init script if not.
You don't mention what OS your server runs, but if it's a recent Ubuntu, you can write an Upstart script pretty easily. It's built-in, and has the important feature of Monit/God - keeping your daemon running, even through restarts.
I use gem eye - https://github.com/kostya/eye
BUNDLE = 'bundle'
RAILS_ENV = 'production'
ROOT = File.expand_path(File.dirname(__FILE__))
Eye.config do
logger "#{ROOT}/log/eye.log"
end
Eye.application :app do
env 'RAILS_ENV' => RAILS_ENV
working_dir ROOT
trigger :flapping, :times => 10, :within => 1.minute
process :passenger do
daemonize true
pid_file "tmp/pids/passenger.pid"
start_command "#{BUNDLE} exec passenger start --port 3000 --environment #{RAILS_ENV}"
stop_signals [:TERM, 5.seconds, :KILL]
restart_command "kill -USR2 {PID}"
restart_grace 10.seconds
check :cpu, :every => 30, :below => 80, :times => 3
check :memory, :every => 30, :below => 70.megabytes, :times => [3,5]
end
process :delayed_job do
pid_file "tmp/pids/delayed_job.pid"
stdall "log/delayed_job.log"
daemonize true
stop_signals [:INT, 30.seconds, :TERM, 10.seconds, :KILL]
restart_grace 10.seconds
start_command "#{BUNDLE} exec rake jobs:work"
end
end
Depending on your platform, you will almost certainly have some variant of init available. On debian, this is init.d. On ubuntu, init.d or upstart. on a RHEL-like, service. These will allow you to manage services on startup. I suggest reading the appropriate man page for your platform.
Related
I have a stack in Elastic Beanstalk running the "Passenger with Ruby 2.5 running on 64bit Amazon Linux/2.8.3" image. Rails is v5.2.1. The desire is to make it a staging environment i.e., have 'Rails.env' return 'staging' and run off of a staging.rb configuration. The problem is, it seems to be running as 'production' no matter what I do.
I set up RACK_ENV and RAILS_ENV as EB configuration variables, both set to 'staging'. I confirmed their existence on the server with 'printenv' as ec2-user, webapp, and root.
I tried changing passenger_app_env in the Passenger config to 'staging'. I've confirmed that Passenger Standalone is using the correct config by looking at the process with 'ps aux | grep passenger'.
I've tried switching to the root server and manually doing '/etc/init.d/passenger stop' and then 'start', and the printout confirms Passenger is launching with its 'environment' set to 'staging':
=============== Phusion Passenger Standalone web server started ===============
PID file: /var/app/support/pids/passenger.pid
Log file: /var/app/support/logs/passenger.log
Environment: staging
Accessible via: http://0.0.0.0/
Serving in the background as a daemon.
Problems? Check https://www.phusionpassenger.com/documentation/Users%20guide%20Standalone.html#troubleshooting
I put this into environment.rb and added an EB config var for STAGING to be 'true'.:
if ENV['STAGING']
%w(RACK_ENV RAILS_ENV).each do |key|
ENV[key] = 'staging'
end
end
However, the test page I made in my Rails app still says 'Rails.env' is 'production', and is not using values from 'staging.rb'. And yet, that same test page says that 'ENV['RACK_ENV']' and 'ENV['RAILS_ENV'] are both set to 'staging'.
At this point, I'm out of ideas on how to force the environment in any other way.
After much hacking, I discovered that Passenger was launching with a passenger_app_env of 'production' (its default) and then switching over to 'staging'. Rails.env would get the the
'production' env and use 'production.rb', then RACK_ENV and RAILS_ENV would be overwritten to 'staging', creating the confusing duality.
The solution was moving the passenger_app_env directive higher up in the Passenger Standalone template that Passenger uses; we had it inside of a server directive inside of an http directive. Moving it up out of the server directive and into the http directive itself solved the issue.
So far I had a simple application that only required the classic rails server to boot.
I have recently added the react_on_rails gem and it requires to boot a nodejs server to handle webpack and javascript stuff.
So I understand I need this foreman gem that is capable of managing several processes. So far so good, but then I'm still having a few problems understanding and deploying this enhanced app to my production environment (Phusion Passenger on Apache/Nginx)
So several questions :
Does passenger handle the transition from rails s to foreman start -f Procfile.dev automatically ?
If no then where do I setup things so passenger works ?
Side question : almost all google results refer to puppet when looking for foreman on passenger. Anyone could explain what puppet does in 1 line and if I really need it in production ? So far everythings runs smoothly on localhost with the foreman start -f Procfile.dev command so I don't know where this is coming from...
I am deploying my application to the Amazon Cloud using Capistrano, and I was expecting to have the rails + nodejs setup on every autoscaled instance (and Passenger would graciously handle all that). Am I thinking wrong ?
In our production environment we use eye to manage other processes related to the rails app. (Passenger will run from mod_passenger while the workers are controlled by eye)
And here is an example of how to start 4 concurrent queue_classic workers:
APP_ROOT = File.expand_path(File.dirname(__FILE__))
APP_NAME = File.basename(APP_ROOT)
Eye.config do
logger File.join(APP_ROOT, "log/eye.log")
end
Eye.application APP_NAME do
working_dir File.expand_path(File.dirname(__FILE__))
stdall 'log/trash.log' # stdout,err logs for processes by default
env 'RAILS_ENV' => 'production' # global env for each processes
trigger :flapping, times: 10, within: 1.minute, retry_in: 10.minutes
group 'qc' do
1.upto(4) do |i|
process "worker-#{i}" do
stdall "log/worker-#{i}.log"
pid_file "tmp/pids/worker-#{i}.pid"
start_command 'bin/rake qc:work'
daemonize true
stop_on_delete true
end
end
end
end
I have the following application defined using application and application_ruby cookbooks:
application 'railsapp' do
owner 'vagrant'
group 'vagrant'
path '/home/vagrant/railsapp'
revision 'master'
repository 'git#github.com:rohshall/railsreadings.git'
migrate true
rails do
bundler true
database do
host 'localhost'
username mysql_connection_info[:username]
password mysql_connection_info[:password]
database 'railsreadings_production'
adapter 'mysql2'
encoding 'utf8'
end
end
unicorn do
preload_app true
port "9000"
worker_timeout 30
worker_processes 2
end
end
Even though I have preload_app true, unicorn is not restarted. I can see from the chef log that unicorn's before_compile cook and before_deploy hooks are executed, but it does not go into before_restart. Any pointers about my mistakes in configuration?
The model with the application cookbook is that it will look for a "restart_command" in each of the registered resources and trigger these between the before_restart and after_restart callbacks. In the previous releases of the application_ruby this would default to "touch tmp/restart.txt" which is the default for passenger. In the current release there is no default restart_command.
I suggest adding a suitable command for unicorn:
application 'railsapp' do
...
restart_command "service unicorn restart"
...
end
Depending on the version of the application_ruby cookbook, you may need to put this under the "rails" resource.
We use these cookbooks extensively at Ninefold in our rails app deployment service and generally they work very well. We find the actual callbacks very useful to over-ride the inbuilt actions such as migrations and asset precompilation to provide better control and reporting.
I have my rails site deployed under apache. The apache is run as a service. Now I have added delayed_job there and things work fine.
Now I want to start the workers together with apache, e.g, After rebooting the server, my site and workers are up and ready so I don't have to log in and type "sudo RAILS_ENV=production script/delayed_job -n 2 start".
Another issue is that whenever I want to start the delayed_job I have to use "sudo"...
Any idea how to avoid those 2 issues?
Thanks for your help.
Use the whenever gem and its 'every :reboot' functionality. In schedule.rb:
environment = ENV['RAILS_ENV'] || 'production'
every :reboot do
command "cd #{path} && #{environment_variable}=#{environment} bin/delayed_job --pool=queue1:2, --pool=queue2,queue3:1 restart"
end
Could you just create a shell script to execute the commands you need?
#!/bin/sh
# stop delayed job
# restart apache
apachectl restart
# start delayed job
sudo RAILS_ENV=production script/delayed_job -n 2 start
It sounds like you want to have delayed_job automatically start after apache starts when you boot up the hardware. If that's the case you need to write an init script in /etc/init.d or /etc/rc.d/init.d (depending on your system). This page gives a decent primer on this:
http://www.philchen.com/2007/06/04/quick-and-dirty-how-to-write-and-init-script
I have some Rails projects on Ruby 1.9.x and some still on 1.8.7. I'm using RVM, and I'm using Phusion's preferred method of defaulting to 1.9 for my main Passenger and using the 1.8.7 (REE)-based projects in standalone mode.
I didn't feel like setting up vhosts for these, so I just bookmarked my dev sites with the localhost and port.
So, to restart, I created this bash script (answering my own question here to help any others) ...
Quick and dirty shell script.
In ~/start_rails.sh:
#!/bin/sh
# Loop through directories of Passenger standalone sites
# and start, incrementing port each time
sites=( rails_site_1 rails_site_2 rails_site_3 )
port=3001
for dir in "${sites[#]}"
do
echo "Switching to ${dir}"
cd ~/Sites/$dir
echo "Starting Passenger on port ${port}"
passenger start -a 127.0.0.1 -p ${port} -d
echo ""
port=$((port+1))
done
Make sure the sites array appears in the order you bookmarked your ports. Call with start_rails.sh.