Primary servers in capistrano - ruby-on-rails

I have a task in capistrano wherein I want just a single line to run only if the server is a marked as primary. Is there a variable or method that I can reference inside a task? 'primary?' or 'primary' doesn't seem to work.
I've also tried something akin to the following:
after "deploy", "task1"
after "deploy", "task2"
after "deploy", "task3"
task :task1, :roles => :app do
*code*
end
task :task2, :roles => :app, :only => {:primary => true} do
*code for just primary server*
end
task :task3, :roles => :app do
*more code*
end
But even this doesn't seem to work (all three tasks get run on every server).
I've been working on this on and off for a few days and I'm having no luck with my searches. Thoughts?

I've solved the issue, but it wasn't pretty. The thing that I've found is that you need to use the 'primary => true' on a per-task basis. Looking at the code, it appears that capistrano generates a list of the servers that the task will be run on before the task is run.

Related

How do I verify if a series of rake tasks ran correctly? Or, what alternatives are there to rake

Somebody has asked a similar question here:
https://github.com/jimweirich/rake/issues/257
The answer from the maintainer was:
I am going to reject this since it allows you to use tasks in non-rake-like ways.
So what are the correct way of using rake if a task depends of other tasks.
task 'succeed' => ['db:drop','stats'] do something end
displays results of stats even if Postgres threw an error and db:drop failded because of active connections.
If rake is not suitable for system maintenace, what tools should I use?
I need to be able to run a backup of a database, then do some tests, then drop the database and finally restore from backup.
to hel you understand my problem look at folowing fragment
namespace :experiment do
desc "TODO"
task 'succeed' => ['stopme', 'stats'] do
puts 'this and stats task should not run'
end
desc "TODO"
task stopme: :environment do
Rake::Task['db:drop'].invoke
end
end
You can invoke tasks manually like that:
task :stats => :environment do
Rake::Task['db:drop'].invoke rescue nil
# do something
end

Multiple delayed_jobs roles with Capistrano?

I have a question that I am not finding much useful information for. I'm wondering if this is possible and, if so, how to best implement it.
We are building an app in Rails which has heavy data-processing in the background via DelayedJob (…it is working well for us.)
The app runs in AWS and we have a few different environments configured in Capistrano.
When we have heavy processing loads, our DelayedJob queues can back up--which is mostly fine. I do have one or two queues that I'd like to have a separate node tend to. Since it would be ignoring the 'clogged' queues, it would keep tending its one or two queues and they would stay current. For example, some individual jobs can take over an hour and I wouldn't want a forgotten-password-email delivery to be held up for 90 minutes until the next worker completes a task and checks for a priority job.
What I want is to have a separate EC2 instance that has one worker launched that tends to two different, explicit queues.
I can do this manually on my dev machine by launching one or two workers with the '--QUEUES' option.
Here is my question, how can I define a new role in capistrano and tell that role's nodes to start a different number of workers and tend to specific queues? Again, my normal delayed_jobs role is set to 3 workers and runs all queues.
Is this possible? Is there a better way?
Presently on Rails 3.2.13 with PostgreSQL 9.2 and the delayed_job gem.
Try this code - place it in deploy.rb after requiring default delayed_job recipes.
# This overrides default delayed_job tasks to support args per role
# If you want to use command line options, for example to start multiple workers,
# define a Capistrano variable delayed_job_args_per_role:
#
# set :delayed_job_args_per_role, {:worker_heavy => "-n 4",:worker_light => "-n 1" }
#
# Target server roles are taken from delayed_job_args_per_role keys.
namespace :delayed_job do
def args_per_host(host)
roles.each do |role|
find_servers(:roles => role).each do |server|
return args[role] if server.host == host
end
end
end
def args
fetch(:delayed_job_args_per_role, {:app => ""})
end
def roles
args.keys
end
desc "Start the delayed_job process"
task :start, :roles => lambda { roles } do
find_servers_for_task(current_task).each do |server|
run "cd #{current_path};#{rails_env} script/delayed_job start #{args_per_host server.host}", :hosts => server.host
end
end
desc "Restart the delayed_job process"
task :restart, :roles => lambda { roles } do
find_servers_for_task(current_task).each do |server|
run "cd #{current_path};#{rails_env} script/delayed_job restart #{args_per_host server.host}", :hosts => server.host
end
end
end
P.S. I've tested it only with single role in hash, but multiple roles should work fine too.
In Capistrano3, using the official capistrano3-delayed-job gem, you can do this without modifying the Capistrano methods:
# If you have several servers handling Delayed Jobs and you want to configure
# different pools per server, you can define delayed_job_pools_per_server:
#
# set :delayed_job_pools_per_server, {
# 'server11-prod' => {
# 'default,emails' => 3,
# 'loud_notifications' => 1,
# 'silent_notifications' => 1,
# },
# 'server12-prod' => {
# 'default' => 2
# }
# }
# Server names (server11-prod, server12-prod) in :delayed_job_pools_per_server
# must match the hostnames on Delayed Job servers. You can verify it by running
# `hostname` on your servers.
# If you use :delayed_job_pools_per_server, :delayed_job_pools will be ignored.

Cron job in ruby on rails not work

I followed the railscast http://railscasts.com/episodes/164-cron-in-ruby but I cant seem to make it worked.
I have schedule.rb in my config.
I wished to refresh my Database.count everyday in my homepage.
I cannot find the deploy.rb in my folder. Where is it?
For testing purpose, I changed it to every 2 seconds.
[schedule.rb]
every '2 * * * *' do
rake "pages_controller:home"
end
[pages_controller.rb]
class PagesController < ApplicationController
def home
#title = "Home"
#companies = Company.find(:all, :limit => 20)
#count = Company.count
end
I have put
gem 'whenever', :require => false
in my gemfile. What have gone missing?
I have used cron job but i run it as rake task please you can try it
every 3.minutes do
set :environment, 'development'
rake "daily",:output => {:error => 'error.log', :standard => 'cron.log'}
end
And my task is like
require 'rubygems'
task :daily => :environment do
puts "i am fine"
# do your code
end
If cron job run fine then there will be nothing in cron.log.Otherwise it will show you if
any error occurs and this file will be generate in your app root directory.
try it..
So... Couple things.
You need a Capfile and a config/deploy.rb to deploy your code using Capistrano and Whenver. You get this by running capify . ... You should most likely watch the railscast on capistrano deployment
Whenever is using configured like:
schedule.rb
every 1.day, :at => '4:30 am' do
runner 'Rails.cache.clear'
end
I really don't think rake "pages_controller:home is going to work unless this is something you've already created elsewhere. I'm further assuming you are caching this page, and that's why you need to refresh the cache.
Finally, you're setting your environment to development, which makes me think you are not deploying this, but instead just wanting to reset the cached home page... So just run rake cache:clear

Why keep a copy of an app on the DB host?

A lot of Capistrano example recipes include a :db role. By default the deploy task exports the app code to all hosts in all roles. So that suggests that it's typical for people to keep a copy of their app on the DB host. Also, in Capistrano's distributed deploy.rb recipe, :deploy:migrate looks like this:
task :migrate, :roles => :db, :only => { :primary => true } do
# ...
end
My question is, why is it done like that? Wouldn't it be cleaner to keep app code off the DB host (which might not even have Ruby installed) and run migrations from the production box?
The db server runs migrations because it is the one 'responsible' for the database(s).
One could also imagine security policies that only allows for creating/dropping/changing of tables from the database server itself.
There might even be slight performance gains if there is data being loaded during a migration, although that is a terrible idea to begin with.
If you have the need to reference your database host and do not need a copy of the code on it you can use something like this:
role :db, 'dbhost', :no_release => true
Sample code to run migrations on an application server:
role :app, 'apphost', :runs_migrations => true
task :migrate, :roles = :app, :only => {:runs_migrations => true } do
#...
end

Are plugins available to a rake task?

When I run a rake task for an application that uses Models defined in a plugin I get an Uninitialized Constant error, but when I run the model process, with script/runner, that is fired in the rake task then the job runs fine?
Is there some difference between script/runner that loads all my plugins that doesn't happen when I fire up a rake task even though it is being passed an environment?
Your rake task needs to be dependent upon :environment. That will spin up your app's environment and give you access to your models, etc.
Eg
desc "Make DB Views"
task :views => [:environment] do |t|
# your task's code
end
You need to specify that your Rake task requires the environment to be loaded:
task :your_task => :environment do |t| ...
or
task :your_task => [:environment] do |t| ...
or
task :your_task, :param1, :param2, :needs => :environment do |t, args| ...
or
task :your_task, :param1, :param2, :needs => [:environment] do |t, args| ...
If you did specify this, then there is another problem. I think one common source of errors is due to the fact that the plugins are loaded inside a namespace called Rails::Plugin. So if you defined a class called Foo in your plugin, then the Rake task needs to reference it as Rails::Plugin::Foo instead of simply Foo.
If this does not solve your problem then try to add puts "Check" on the first line of the plugin's init.rb file, and make sure that Check is displayed when you run your rake task. If it is, then your plugin is being loaded, but perhaps it fails silently after that.
One last thing: maybe you are trying to use the plugin outside the task, for example at the beginning of your Rake file, in some initialization code? If so, then it will fail because the plugins only get loaded when the task is executed (when the environment is loaded).
Hope this helps.

Resources