Skip to content

Instantly share code, notes, and snippets.

@mikewadhera
Created January 7, 2009 03:36
Show Gist options
  • Save mikewadhera/44161 to your computer and use it in GitHub Desktop.
Save mikewadhera/44161 to your computer and use it in GitHub Desktop.
an example leveraging jruby-rack jms for background queue + cron in rails
require 'queueable'
class ApplicationTasks
include Queueable
end
namespace :cron do
desc "Work to run every 10 minutes"
task :ten_minutes => :bootstrap do
log_interval :ten_minutes do
FacebookAppTasks.fire_send_pending_emails
...
end
end
desc "Work to run every 30 minutes"
task :half_hourly => :bootstrap do
log_interval :half_hourly do
end
end
desc "Work to run every 60 minutes"
task :hourly => :bootstrap do
log_interval :hourly do
CampaignFeatureTasks.fire_refresh_rss_caches
...
end
end
desc "Work to run every day after 12:01am"
task :daily => :bootstrap do
log_interval :daily do
BusinessTasks.fire_analyze_opportunities
...
end
end
desc "Bootstraps cron environment"
task :bootstrap => :environment do
ApplicationTasks.logger = Logger.new("#{RAILS_ROOT}/log/cron.log")
end
# Helper method for logging start/end times for a block of work
def log_interval(interval)
ApplicationTasks.logger.info("**** Performing #{interval.to_s.humanize} work at #{Time.now.strftime("%Y-%m-%d %H:%M:%S")}")
duration = Benchmark.realtime { yield }
ApplicationTasks.logger.info("**** Finished #{interval.to_s.humanize} work at #{Time.now.strftime("%Y-%m-%d %H:%M:%S")} (took #{format("%.2f", duration)} seconds) \n")
end
end
*/9 * * * * cd $rails_root && $jruby -S rake RAILS_ENV=production cron:ten_minutes 2>&1
0,30 * * * * cd $rails_root && $jruby -S rake RAILS_ENV=production cron:half_hourly 2>&1
56 * * * * cd $rails_root && $jruby -S rake RAILS_ENV=production cron:hourly 2>&1
15 0 * * * cd $rails_root && $jruby -S rake RAILS_ENV=production cron:daily 2>&1
require 'benchmark'
module Queueable
def self.included(target)
target.extend(ClassMethods)
end
def on_exception(exception)
logger.error('Task Error: ' + exception.message)
exception.backtrace.each { |line| logger.error("\t#{line}") }
logger.error("\n")
raise(exception) if !self.class.queueable?
end
def logger
self.class.logger
end
module ClassMethods
def queueable?
defined?($servlet_context)
end
def method_missing(m, *args)
super unless m.to_s.match /^fire_/
task = {
:class => self.name.to_s,
:action => m.to_s.sub(/^fire_/, ''),
:args => args
}
fire(task)
end
def fire(task)
if queueable?
JRuby::Rack::Queues.send_message('rack', task)
else
call(task)
end
end
# Called-back by fire directly or via queue manager with deserialized message
def call(task)
klass = task[:class].constantize
proxy = klass.new
action = task[:action]
args = task[:args]
logger.info("Starting task: #{klass.name}##{action} at #{Time.now.strftime("%Y-%m-%d %H:%M:%S")}")
logger.info(" Arguments: #{args.empty? ? '(None)' : args.map { |arg| arg.inspect }.join(',')}")
begin
duration = Benchmark.realtime { proxy.send(action, *args) }
logger.info("Completed task: #{klass.name}##{action} at #{Time.now.strftime("%Y-%m-%d %H:%M:%S")} (took #{format("%.2f", duration)} seconds) \n")
rescue => exception
proxy.on_exception(exception)
end
end
def logger
@logger ||= Logger.new("#{RAILS_ROOT}/log/jms.log")
end
def logger=(logger)
@logger = logger
end
end
end
# This initializer contains code we only want to load in a servlet context
if defined?($servlet_context)
...
# Add JRuby-Rack Queues support
require 'jruby/rack/queues'
JRuby::Rack::Queues.register_listener("rack", ApplicationTasks)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment