Executing Rails 'whenever' gem when EC2 Instance Moves - ruby-on-rails

I use the 'whenever' gem for my rails cron file in EC2 and it works great. "Whenever -w" writes it and I never have to worry about it again. The problem is when my instance has a planned reboot. The rails app get passed to a new instance and the whole process is seamless with no downtime, but the new instance does not have my cron file.
How can I make sure that the cron file gets written when I move to a new instance? Is there a way to run it on app start or something like that? Thanks.

Whenever is a command. If you run:
bundle exec whenever --help
You will get a full list of flags. You'll want:
bundle exec whenever -w /path/to/schedule.rb
You can add a simple shell script to /etc/init.d
#!/bin/bash
cd /to/app && /full/path/to/bundle exec whenever -w /full/path/to/schedule.rb

Related

Run Capistrano Command on Instance Startup

I am running a Rails 3.2.18 application on AWS. This application is deployed using Capistrano, including starting Resque workers for the application.
My problem is that AWS can occasionally restart instances with little to no warning, or an instance can be restarted from the AWS console. When this happens, Resque is not started as it is during our normal deployment process.
I have tried to create a shell script in /etc/init.d to start Resque on boot, but this script continues to prompt for a password, and I'm not sure what I'm missing. The essence of the start script is:
/bin/su -l deploy-user -c "/www/apps/deploy-user/current && bundle exec cap <environment> resque:scheduler:start resque:start"
Obviously the above command works as expected when run as the "deploy" user from the bash prompt, but when run via sudo /etc/init.d/resque start, it prompts for a password upon running the first Capistrano command.
Is there something glaring that I am missing? Or perhaps is there a better way to accomplish this?
You should run su with -c parameter to specify commands, and enclose all commands within double quotes:
/bin/su -l deploy-user -c "/www/apps/deploy-user/current && bundle exec cap <environment> resque:scheduler:start resque:start"
Of course, you have other alternatives, like /etc/rc.local.
But if you're going to use an init.d script, I'd suggest to create it propperly (at least start/stop, default runlevels...). Otherwise I'd go with /etc/rc.local or even with a cron job for the deploy-user:
#reboot /www/apps/deploy-user/current && bundle exec cap <environment> resque:scheduler:start resque:start

Run a command in the context of a different app

I have two rails apps on the same server, let's call them A and B.
I am trying to have app A restart app B via app B's own capistrano task. Unfortunately, even after cd-ing to app B's directory, it is trying to run app A's capistrano instead. Am I missing something?
example code
system("cd /apps/appB/current && pwd && bundle exec cap:restart")
pwd correctly returns the path of appB (/apps/appB/current), however, in there is a traceback for cap:restart. This is because it is still trying to run the cap command in the context of appA, e.g.
/apps/appA/shared/bundle/ruby/1.9.1/gems/capistrano-2.15.4/lib/capistrano/configuration/loading.rb:152:in 'require': cannot load such file -- airbrake/capistrano (LoadError)
from /apps/appA/shared/bundle/ruby/1.9.1/gems/capistrano-2.15.4/lib/capistrano/configuration/loading.rb:152:in 'require'.
I tried without 'bundle exec', and have tried some other ways of making system calls. I also created a bash script in another directory and tried to run it that way.
All methods described exhibit the same behaviour.
Your help would be greatly appreciated =)
You need to use Bundler.with_clean_env to ensure that your subprocess doesn't pick up your current Bundler environment:
Bundler.with_clean_env do
system("cd /apps/appB/current && pwd && bundle exec cap:restart")
end
This is essentially the same problem as Install bundle of gem within other rails application
Since you said your apps are using Unicorn, you can signal from app A to app B (or the other way around).
Read this page: http://unicorn.bogomips.org/SIGNALS.html
The only thing each application needs to know is the pidfile path of the other application. So look at your Unicorn config and see where it's storing that.
You could either read the PID out of that pidfile and kill it from Ruby:
pid = File.read(path_to_other_application_pidfile).chop
Process.kill("USR2", pid)
Or you could use backticks to execute shell commands
`kill -s USR2 \`cat #{path_to_other_application_pidfile}\``

Scheduling rake task with cron

I'm trying to set daily cron job to update my site stats, but it looks like it doesn't work.
Cron entry (for deployer user):
0 0 * * * cd /var/www/my_site/current && rake RAILS_ENV=production stats:update
I'm running ubuntu server, with rbenv.
Any idea what's wrong?
Many times $PATH is defined differently when cron runs compared to when you are working in your own shell. Do "whereis rake" to find the full path to rake and then replace "rake" with its full path. (I am assuming that the "cd" command is working, so I am focusing on whether "rake" is found / running properly.)
Has cron sent you any emails with error messages after you added your command to your crontab?
You might want to run "crontab -l" under the proper user account to make sure that your cron command is actually registered within the crontab, especially if you aren't receiving any emails.
The presence of a Gemfile can also affect the ability to properly run rake. See, for example, Error: "Could not find rake", yet Rake is installed

How to autostart Rails delayed jobs?

I'm using delayed job to create job queues such as 'mailer'
For this to work I have to run this:
$ RAILS_ENV=development QUEUE=mailer rake jobs:work
But if the server crashes and is restarted, I need the worker to start running again automatically.
What would be the recommended way to deal with this?
You need to use a third-party service like monit/bluepill/god/upstart to watch the process and restart it. I recommend using the combination of foreman and upstart. See here: http://blog.daviddollar.org/2011/05/06/introducing-foreman.html
Some time ago I wrote a patch for the DelayedJob to reload the classes for every job in development mode. Same patch should work for your requirement also.
betamatt's approach is definitely one way to do it if you have such a monitoring tool in place.
Another way to do it would simply be to add a script to your OS's startup which runs the RAILS_ENV=development QUEUE=mailer rake jobs:work command under a user who has the necessary permissions.
Here's an example of how to do it on Ubuntu using Upstart, but if you lookup similar init.d methods, or whatever is the relevant for your server OS, you'll find other ways. What you're looking for, basically, is "How to run a script on startup [your OS name]", and then wrap your command in an executable script.
I had the same issue with my application am working with. So i wrote a rake task which runs every minute(as a cron job). When delayed job starts it will create a .pid file in the temp folder. I used this to check the existence of a delayed job process. If the file doesn't exist i ran the console command through code.
delayed_job_status = File.file?("./tmp/pids/delayed_job.pid")
This will check the existence of process. If nil response go to next statement
./bundle exec script/delayed_job start production
This will start delayed job
My solution was creating the bash script in user's home "delayed_job_startup.sh"
which contain
#!/bin/bash
cd /home/deploy/project/current/
RAILS_ENV=production bin/delayed_job start
and in file /etc/rc.local I run this script from my user
su -s /bin/bash - deploy /home/deploy/delayed_job_startup.sh

How to stop cron jobs created by "whenever" gem

I'm using the "whenever" gem and got it working by doing:
whenever --set environment=production --update-crontab theCronJob
The interval I'm using is 2 minutes since I'm still trying to figure it out. However, now I get a You have mail message in my terminal window every 2 minutes. I guess the cron runs and lets me know about it. How do I stop my cron from running? These messages are starting to pile up.
Thank you
To delete the auto-generated cronjobs from your crontab, run whenever against your defintion file with the -c flag:
$ whenever -c theCronJob
Alternatively, open your crontab...
$ crontab -e
... and then manually delete the undesired entries.
following will delete the scheduled crontab:
crontab -r

Resources