Does anyone have experience/success using the whenever gem on aws opsworks? Is there a good recipe? Can I put that recipe on a separate layer and associate one instance with that additional layer? Or is there a better way to do it? Thanks!!!
EDIT:
We ended up doing it a bit differently...
Code:
Can’t really post the real code, but it’s like this:
in deploy/before_migrate.rb:
[:schedule].each do |config_name|
Chef::Log.info("Processing config for #{config_name}")
begin
template "#{release_path}/config/#{config_name}.rb" do |_config_file|
variables(
config_name => node[:deploy][:APP_NAME][:config_files][config_name]
)
local true
source "#{release_path}/config/#{config_name}.rb.erb"
end
rescue => e
Chef::Log.error e
raise "Error processing config for #{config_name}: #{e}"
end
end
in deploy/after_restart.rb:
execute 'start whenever' do
cwd release_path
user node[:deploy][:APP_NAME][:user] || 'deploy'
command 'bundle exec whenever -i APP_NAME'
end
in config/schedule.rb.erb:
<% schedule = #schedule || {} %>
set :job_template, "bash -l -c 'export PATH=/usr/local/bin:${PATH} && :job'"
job_type :runner, 'cd :path && bundle exec rails runner -e :environment ":task" :output'
job_type :five_runner, 'cd :path && timeout 300 bundle exec rails runner -e :environment ":task" :output'
set :output, 'log/five_minute_job.log'
every 5.minutes, at: <%= schedule[:five_minute_job_minute] || 0 %> do
five_runner 'Model.method'
end
We have a whenever cookbook in our repo we use that you would be more than welcome to use here: https://github.com/freerunningtech/frt-opsworks-cookbooks. I assume you're familiar with adding custom cookbooks to your opsworks stacks.
We generally run it on its own layer that also includes the rails cookbooks required for application deployment (while not the app server):
Configure: rails::configure
Deploy: deploy::rails whenever
Undeploy: deploy::rails-undeploy
However, we usually also deploy this instance as an application server, meaning we do end up serving requests from the box we're using for whenever as well.
There is one "gotcha", in that you must set your path in the env at the top of the schedule.rb like this:
env :PATH, ENV['PATH']
Related
I have an application that contains a bunch of tasks, and every 3 minutes I want to run a cron job that sends a mail for some test. I'm using the whenever gem but it doesn't seem to be running at all.Any ideas?
config/schedule.rb
every 3.minutes do
runner "MailerClass.some_method"
end
MailerClass.rb
def some_method
mail(:to => "some email", :cc => 'some email', :subject => "Regular Email by rake task #{Time.now.strftime("%H : %m")}", :from => "default_sender#udk.com") do |format|
end
end
What I have Tried after modifing config/schedule.rb are,
whenever --update-crontab --set environment=development
sudo service cron restart
When I run
crontab -l
this is the output
0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57 * * * * /bin/bash -l -c 'cd /home/my_app && script/rails runner -e development '\''MailerClass.some_method'\'' >> log/notification.log 2>&1'
I have checked the log. The problem is
script/rails: line 6: syntax error near unexpected token ('
script/rails: line 6:APP_PATH = File.expand_path('../../config/application', FILE)'
I am not getting this. I am new to rails. Thats why may be :(.
Any Solution!!!
It looks like you are forgetting to actually send the email
Instead of
MailerClass.some_method
try
MailerClass.some_method.deliver
Based on your updated info i am updaing my answer
Remove last single quote form end of parenthesis form this line APP_PATH = File.expand_path('../../config/application', FILE)'
I need to send some emails weekly.
I installed the mailer and did several tests. Is working properly.
But I can not use Whenever to automatically send emails.
Have searched in various forums and still can not fix.
Model/HrCurriculumIntern
def self.send_reply_interns
#users = HrCurriculumIntern.where(:answer_sent => t('labels.n'))
InternMailer.send_reply_interns(#users).deliver
end
Mailer/InternMailer
default :from => "username.mailer#gmail.com"
def send_reply_interns(users)
#users = users
mail(:to => "<lorenadgb#gmail.com>", :subject => t('subjects.send_reply_interns'), :from => "username.mailer#gmail.com")
end
COnfig/schedule.rb
set :environment, :development
every 2.minutes do
runner "HrCurriculumInterns.send_reply_interns"
end
I followed this steps:
Eu segui estes passos:
wheneverize .
whenever
0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58 * * * * /bin/bash -l -c 'cd /var/www/form/3216/email/trunk && script/rails runner -e development '\''HrCurriculumInterns.send_reply_interns'\'''
## [message] Above is your schedule file converted to cron syntax; your crontab file was not updated.
## [message] Run `whenever --help' for more options.
whenever –update-crontab
0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58 * * * * /bin/bash -l -c 'cd /var/www/form/3216/email/trunk && script/rails runner -e development '\''HrCurriculumInterns.send_reply_interns'\'''
## [message] Above is your schedule file converted to cron syntax; your crontab file was not updated.
## [message] Run `whenever --help' for more options.
I can't see the problem, any suggestion please?
Use the shortcut "whenever -w" to write the crontab. It looks like you used "whenever -update-crontab" instead of "whenever --update-crontab". So neither of your commands actually wrote the crontab file. The response should be
[write] crontab file updated
After that use "crontab -l" to verify that the correct cron was written.
I found the solution.
My code was wrong. I did some alterations:
Mailer/intern_mailer.rb
def send_reply_interns
#users = HrCurriculumIntern.where(:answer_sent => t('labels.n'))
mail(:to => "<lorenadgb#gmail.com>", :subject => t('subjects.send_reply_interns'), :from => "username.mailer#gmail.com")
end
Models/hr_curriculum_intern.rb
def self.send_reply_interns
InternMailer.send_reply_interns.deliver
end
schedule.rb
set :environment, :development
every 2.minutes do
runner "HrCurriculumIntern.send_reply_interns"
end
Its works now \ o /
Thanks for reply
i'm trying to understand how capistrano 3.1 is working, but because of its lack of documentation (its capistrano, so...), im running below my understanding.
Let me explain.
Here's a snippet taken from capistrano/rails gem
namespace :deploy do
desc 'Runs rake db:migrate if migrations are set'
task :migrate => [:set_rails_env] do
on primary fetch(:migration_role) do
within release_path do
with rails_env: fetch(:rails_env) do
execute :rake, "db:migrate"
end
end
end
end
#[...]
end
when execute cap integration deploy:migrate, it sends the following command:
cd /srv/app/releases/20131106101722 && ( RAILS_ENV=integration /tmp/app/rvm-auto.sh . rake assets:precompile )
I changed a little bit the (non-working) code provided for delayed_job into that
namespace :delayed_job do
def args
fetch(:delayed_job_args, '')
end
def delayed_job_roles
fetch(:delayed_job_server_role, :app)
end
def delayed_job_bin
fetch(:delayed_job_bin, :'bin/delayed_job')
end
desc 'Restart the delayed_job process'
task :restart do
on roles(delayed_job_roles) do
within release_path do
with rails_env: fetch(:rails_env) do
execute delayed_job_bin, 'restart', args
end
end
end
end
end
And i get the following command cd /srv/winddle/current && ( RAILS_ENV=integration bin/delayed_job restart )
Obviously, it misses the bundle exec command.
I dive deeply into capistrano/bundler and capistrano/rails to look for some kind of hook that would add bundle exec automatically to any of these commands (or force the register of ssh kits commands) but couldnt find any.
The only solution i found is to use
execute :bundle, :exec, delayed_job_bin, :start, args which is not acceptable of course.
Anyone proper solution / explanation is welcomed.
Regards
Add the following line in deploy.rb, then use the code provided by delayed_job other than changing script to bin, which I see you already did:
set :bundle_bins, fetch(:bundle_bins, []).push('bin/delayed_job')
For users of RVM, add this instead:
set :rvm_map_bins, fetch(:rvm_map_bins, []).push('bin/delayed_job')
Source: https://github.com/capistrano/bundler#usage.
I'm literally just starting out with Capistrano and also struggling against a lack of documentation, so sorry if this post misses the mark.
v3 relies a lot on sshkit, so reading the documentation for that should be a big help. The readme gives an example that may solve your problem.
SSHKit.config.command_map.prefix[:rake].push("bundle exec")
puts SSHKit.config.command_map[:rake]
# => bundle exec rake
I also found an alternative solution in a Semaphore blog post.
SSHKit.config.command_map[:rake] = "bundle exec rake"
SSHKit.config.command_map[:rails] = "bundle exec rails"
I tried to a records cleanup after certain period of time (6 month) using gem 'whenever'.
In my whenever scheduler :
every 1.month, at: '1am' do
rake 'lib/tasks/cleanup_user.rake'
end
In the lib/tasks/cleanup_user.rake
#user = User.all.where(:created_at > 'Time.6.month.ago').delete
It seems about right. However, I got error 'uninitialized constant User'. I am relatively new in rails. Please assist me.
EDIT : I changed the game by run clean one line command :
set :output, "log/cron.log"
every 1.minutes, :environment => :development do
command 'User.where("confirmed = 0 AND created_at <= ?", 6.months.ago).delete'
end
I set the specific environment,and run this in command :
whenever --set environment=development --update-crontab userscleaning
Checking at crontab, its there but still not work. Any thought?
Try adding the environment dependency to your task.
task :cleanup_users => :environment do
User.where(:created_at > 'Time.6.month.ago').delete_all
end
If you want the callbacks to trigger, use destroy_all
task :cleanup_users => :environment do
User.where(:created_at > 'Time.6.month.ago').destroy_all
end
Here is a relevant Railscasts.
According to the answers here:
# lib/tasks/delete_old_records.rake
namespace :delete do
desc 'Delete records older than 6 months'
task old_records: :environment do
User.where('created_at > ?', 6.month.ago).destroy_all
end
end
Run with:
RAILS_ENV=production rake delete:old_records
In whenever:
every 1.minutes do
rake "delete:old_records"
end
Or in cron:
0 8 * * * /bin/bash -l -c 'cd /my/project/releases/current && RAILS_ENV=production rake delete:old_records 2>&1'
I work with less technical stakeholders and testers on producing a Rails 3.1 app who benefit greatly from seeing the HTML output rendered by my Cucumber and RSpec tests.
I would like a way to bundle this output with the app when I deploy, but am struggling to find the cleanest way to do this. The repo is on Github and we deploy with Capistrano. I would strongly prefer keep this out of version control.
Is anyone else doing this? Thanks!
the cukes are a bit easier... add a rake task:
desc "runs cucumber features and outputs them to doc/cucumber as html"
task :html do
Dir.glob("features/*.feature").each do |story|
system("cucumber",
"#{story}",
"--format=html",
"-o",
"doc/cucumber/#{story.gsub(/features\/(\w*).feature/, '\1.html')}")
end
end
I don't know why the obvious solution didn't occur to me earlier: gitignore the doc files and add a deployment task to scp the files directly into the app's public directory.
.gitignore
public/doc
lib/tasks/doc.rake
namespace :doc do
desc "run features and specs then generate pages accessible in public/doc"
task :html do
# Delete old files
puts "Clearing out old html files..."
system("rm -rf public/doc/")
system("mkdir public/doc/")
# Generate the feature html files
puts "Generating Cucumber html files..."
system("mkdir public/doc/features")
Dir.glob("features/**/*.feature").each do |story|
system("bundle exec cucumber #{story} --drb --format=html -o public/doc/#{story.gsub(/(\w*).feature/, '\1.html')}")
puts "public/doc/#{story}"
end
# Generate RSpec html files
puts "Generating RSpec html files..."
system("mkdir public/doc/spec/")
Dir.glob("spec/**/*_spec.rb").each do |spec|
system("bundle exec rspec #{spec} --drb --format html -o public/doc/#{spec.gsub(/(\w*).rb/, '\1.html')}")
end
# Generate the index file
puts "Writing index file..."
system("echo \"<html><head><title>Doc</title></head><body>\" > public/doc/index.html")
# Write test report navigation
Dir.glob("public/doc/**/*.html").each do |file|
unless file == 'public/doc/index.html'
file.gsub!(/\public\/doc\//, '')
system("echo \"<p><a href='#{file}'>#{file.gsub('.html', '')}</a></p>\" >> public/doc/index.html")
end
end
# Close index.html file
system("echo \"</body></html>\" >> public/doc/index.html")
puts "Done!"
end
end
config/deploy.rb
desc "Generate Cucumber & RSpec HTML docs"
task :generate_docs, :roles => :app do
system("bundle exec rake doc:html")
end
desc "Copy Cucumber & RSpec HTML docs outside of version control with scp"
task :copy_docs, :roles => :app do
system("tar -zcvf tmp/doc.tar.gz public/doc && rm -rf public/doc")
system("scp -r -i ~/myKey.pem tmp/doc.tar.gz #{user}##{hostname}:#{deploy_to}/current/public/doc.tar.gz && rm tmp/doc.tar.gz")
run "cd #{release_path}; tar -zxvf public/doc.tar.gz && rm public/doc.tar.gz"
end
after 'deploy', 'docs:generate_docs', 'docs:copy_docs'