Cron Job Rails 3 - Loading system ruby not RVM ruby - ruby-on-rails-3

I'm trying to set up a cron job with the following command:
crontab -l
Begin Whenever generated tasks for: myapp
* * * * * /bin/bash -l -c 'cd /Users/boris/projects/myapp && script/rails runner "Resque.enqueue(MyModel)"'
I get the following error; in which I see its loading Ruby 1.8. The problem is I'm using RVM with ruby 1.9.2. How do I specify the correct RVM path in CRON?
Subject: Cron <boris#jz> /bin/bash -l -c cd /Users/boris/projects/myapp && script/rails runner "Resque.enqueue(Place)"
X-Cron-Env: <SHELL=/bin/sh>
X-Cron-Env: <PATH=/usr/bin:/bin>
X-Cron-Env: <LOGNAME=boris>
X-Cron-Env: <USER=boris>
X-Cron-Env: <HOME=/Users/boris>
Message-Id: <20110523022400.A5B242C608D#jz.local>
Date: Sun, 22 May 2011 19:24:00 -0700 (PDT)
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/rubygems/custom_require.rb:31:in `gem_original_require': no such file to load -- bundler/setup (LoadError)
from /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/rubygems/custom_require.rb:31:in `require'
from /Users/boris/projects/myapp/config/boot.rb:6
from script/rails:5:in `require'
from script/rails:5
How do I specify the correct RVM path in CRON?
Thanks in advance
Ruby path with which ruby:
/Users/boris/.rvm/rubies/ruby-1.9.2-p180/bin/ruby

Please do not use the -l switch in cron jobs. The --login switch instructs bash to run as a login shell. Therefore, it will load your environment, and things might appear to work. However, cron jobs are by nature non-interactive, non-login shells. Invoking them as if they were is just bad practice. Also, when bash starts a login shell, it first loads the system environment (/etc/profile), and if in that file something needs to print to the screen (like motd), your cron job will report nasty errors like this:
stty: TIOCGETD: Inappropriate ioctl for device
You don't need to write a cron runner neither (following that logic, you might as well write a cron runner runner). Please keep things simple. All you need to do is configure your cron job to launch a bash shell, and make that bash shell load your environment.
The shebang line in your script should not refer directly to a ruby executable, but to rvm's ruby:
#!/usr/bin/env ruby
This instructs the script to load the environment and run ruby as we would on the command line with rvm loaded.
On many UNIX derived systems, crontabs can have a configuration section before the actual lines that define the jobs to be run. If this is the case, you would then specify:
SHELL=/path/to/bash
This will ensure that the cron job will be spawned from bash. Still, your environment is missing, so to instruct bash to load your environment, you will want to add to the configuration section the following:
BASH_ENV=/path/to/environment (typically .bash_profile or .bashrc)
HOME is automatically derived from the /etc/passwd line of the crontab owner, but you can override it.
HOME=/path/to/home
After this, a cron job might look like this:
15 14 1 * * $HOME/rvm_script.rb
What if your crontab doesn't support the configuration section. Well, you will have to give all the environment directives in one line, with the job itself. For example,
15 14 1 * * export BASH_ENV=/path/to/environment && /full/path/to/bash -c '/full/path/to/rvm_script.rb'
Full blog post on the subject

Your problem is that you're executing two commands but not as you expect. The two commands are:
/bin/bash -l -c cd /Users/boris/projects/myapp
script/rails runner "Resque.enqueue(MyModel)"
With the second only executing if the first succeeded. I think you just need some quotes:
* * * * * /bin/bash -l -c 'cd /Users/boris/projects/myapp && script/rails runner "Resque.enqueue(MyModel)"'
Those single quotes will feed your cd ... && script/rails ... pair to /bin/bash as a single command and that should change the current working directory to what you want when script/rails is executed.

Easiest solution is to use this command instead:
Begin Whenever generated tasks for: myapp
* * * * * /bin/bash -l -c 'cd /Users/boris/projects/myapp && ./script/rails runner "Resque.enqueue(MyModel)"'

Related

New Ubuntu RVM package - I used to use the wrappers binary folder for executables, but which one now?

whenever I run my install scripts for deploying new code, I used to use the /home/<$USER>/.rvm/gems/ruby-2.6.5/wrappers/bundle folder for hard coding executable paths to bundler
Since I see that there is now a separate installation now specifically for ubuntu and that folder path no longer exists, what should I use in my install scripts?
doing things like the following in my deployment scripts does not seem to find bundle
sudo -u <my-user> bash << eof
echo 'remove the current cron tasks'
crontab -r
echo 'running bundle install'
bundle install
echo 'install cron tasks'
(crontab -l 2>/dev/null; echo "00 13 * * * /bin/bash /var/www/application/bin/daily.sh")| crontab -
crontab -l
eof

how to run rake task in background in rails

This is my command
bundle exec rake resque:work QUEUE="*" --trace
I want to run this command on my server as a background process.
please help me.
A method I often use is:
nohup bundle exec rake resque:work QUEUE="*" --trace > rake.out 2>&1 &
This will keep the task running even if you exit your shell. Then if I want to just observe trace output live, I do:
tail -f rake.out
And you can examine rake.out at any time.
If you need to kill it before completion, you can find it with ps and kill the pid.
Just in case somebody finds this 4 years later, bundle has an elegant way of doing this now. For example if you want to run sidekiq in the background you can do:
bundle exec sidekiq -e production -d -L ./log/sidekiq.log
The -d daemonizes to run in the background, but you will also need to use the -L to provide a logfile, else bundler will refuse to run your command in the background (deamonize).
Tested with bundler version 1.15.4
Update Oct 2019.
While the command still works in general, the specific command above will no longer work for sidekiq 6.0+, you'll need to use Upstart or Systemd if you use Linux: https://github.com/mperham/sidekiq/wiki/Deployment#running-your-own-process

dead simple chef rvm installation script fails

What I have: Chef;
What I need: RVM installed for node[:deploy][:user][:name]. I need user-wide install, not system-wide.
What I tried latest:
script 'install_rvm' do
user = node[:deploy][:user][:name]
interpreter '/bin/bash'
code "su -l #{user} -c '\curl https://raw.github.com/wayneeseguin/rvm/master/binscripts/rvm-installer | bash -s stable'"
not_if { ::File.exists? "/home/#{user}/.rvm" }
end
When I manually run su -l <username> -c '\curl <long_url> | bash -s stable' on test server surely it works perfectly.
I expect Chef to run the same code, and in logs it seems like it does, but the next execute resource fails because in fact there is no /home/<username>/.rvm present.
Yes I know that in Chef I can specify user as user node[:deploy][:user][:name] instead of changing user with su but for some reason if I do that rvm would try to install itself in /root/.rvm (env not properly reset?).
Well, I would like to ask, why is Chef so extremely crappy even for such dead-simple tasks, but it looks like I've chosen the wrong place, so the question is what am I doing wrong or do I miss something obvious?
why not use chef-rvm from Fletcher Nichol - it is the supported way to deal with RVM in Chef.
Well, at least that worked and may be useful if all better ways to do it with Chef fail for you. Here is the resource for installing ruby
execute 'install_rvm' do
user('root')
user = node[:deploy][:user][:name]
command "su -l #{user} -c '\curl https://raw.github.com/wayneeseguin/rvm/master/binscripts/rvm-installer | bash -s stable'"
not_if { ::File.exists? "/home/#{user}/.rvm" }
end
And the bonus one to create gemset if it is not already present:
execute 'rvm_install_ruby' do
user('root')
user = node[:deploy][:user][:name]
ruby = node[:deploy][:ruby]
gemset = node[:deploy][:gemset]
command "su -l #{user} -c 'rvm use #{ruby}##{gemset} --install --create'"
not_if do
if latest_patchlevel = `rvm list`.scan(/(ruby-#{ruby}-p)(\d+)/).map{ |a| a.last.to_i }.sort.last
`rvm list gemsets`.match /ruby-#{ruby}-p#{latest_patchlevel}##{gemset}/
end
end
end

Why is my cron Job not running on OS X (configured by whenever gem)?

I have set up a cron job, using the great whenever gem.
every 1.minute do
runner "PeerReview.start_feedbacks"
end
I set up the cron job with:
whenever --set environment=development --update-crontab
The crontab file looks fine, it shows:
* * * * * /bin/bash -l -c 'cd /path_to_app/ && script/rails runner -e development '\''PeerReview.start_feedbacks'\'' >> log/cron_log.log 2>&1'
If I execute the runner, it works fine, however, the cron job doesn^t seem to work (also I don't see a log being created).
What am I missing?
(I'm working on Mac OS X, 10.6.6)
update
I think I identified the problem: The path name contains spaces, and this wasn't handled correctly by the whenever gem, the crontab was filled incorrectly (the needed backslashes are missing), so the cronjobs are executed, but the path for the command is wrong.
All above was correctly done.
The rails app was in a directory with spaces in the path names, those spaces were not escaped by the whenever gem, when setting up the crontab.

How to shorten an inittab process entry, a.k.a., where to put environment variables that will be seen by init?

I am setting up a Debian Etch server to host ruby and php applications with nginx. I have successfully configured inittab to start the php-cgi process on boot with the respawn action. After serving 1000 requests, the php-cgi worker processes die and are respawned by init. The inittab record looks like this:
50:23:respawn:/usr/local/bin/spawn-fcgi -n -a 127.0.0.1 -p 8000 -C 3 -u someuser -- /usr/bin/php-cgi
I initially wrote the process entry (everything after the 3rd colon) in a separate script (simply because it was long) and put that script name in the inittab record, but because the script would run its single line and die, the syslog was filled with errors like this:
May 7 20:20:50 sb init: Id "50" respawning too fast: disabled for 5 minutes
Thus, I got rid of the script file and just put the whole line in the inittab. Henceforth, no errors show up in the syslog.
Now I'm attempting the same with thin to serve a rails application. I can successfully start the thin server by running this command:
sudo thin -a 127.0.0.1 -e production -l /var/log/thin/thin.log -P /var/run/thin/thin.pid -c /path/to/rails/app -p 8010 -u someuser -g somegroup -s 2 -d start
It works apparently exactly the same whether I use the -d (daemonize) flag or not. Command line control comes immediately back (the processes have been daemonized) either way. If I put that whole command (minus the sudo and with absolute paths) into inittab, init complains (in syslog) that the process entry is too long, so I put the options into an exported environment variable in /etc/profile. Now I can successfully start the server with:
sudo thin $THIN_OPTIONS start
But when I put this in an inittab record with the respawn action
51:23:respawn:/usr/local/bin/thin $THIN_OPTIONS start
the logs clearly indicate that the environment variable is not visible to init; it's as though the command were simply "thin start."
How can I shorten the inittab process entry? Is there another file than /etc/profile where I could set the THIN_OPTIONS environment variable? My earlier experience with php-cgi tells me I can't just put the whole command in a separate script.
And why don't you call a wrapper who start thin whith your options?
start_thin.sh:
#!/bin/bash
/usr/local/bin/thin -a 127.0.0.1 -e production -l /var/log/thin/thin.log -P /var/run/thin/thin.pid -c /path/to/rails/app -p 8010 -u someuser -g somegroup -s 2 -d start
and then:
51:23:respawn:/usr/local/bin/start_thin
init.d script
Use a script in
/etc/rc.d/init.d
and set the runlevel
Here are some examples with thin, ruby, apache
http://articles.slicehost.com/2009/4/17/centos-apache-rails-and-thin
http://blog.fiveruns.com/2008/9/24/rails-automation-at-slicehost
http://elwoodicious.com/2008/07/15/nginx-haproxy-thin-fastcgi-php5-load-balanced-rails-with-php-support/
Which provide example initscripts to use.
edit:
Asker pointed out this will not allow respawning. I suggested forking in the init script and disowning the process so init doesn't hang (it might fork() the script itself, will check). And then creating an infinite loop that waits on the server process to die and restarts it.
edit2:
It seems init will fork the script. Just a loop should do it.