Skip to content

How to set rankings (and reputation in general) using a background job?

Gaurav Tiwari edited this page May 13, 2015 · 1 revision

Background job for calculating rankings

Rank rules can be run in the background, for instance running a small rake task as part of a cron job. Create a file lib/tasks/cron.rake like:

task :daily_cron_job => :environment do
  Merit::RankRules.new.check_rank_rules
end

Then run rake daily_cron_job as part of a daily cron job (or hourly,however you need), and it will compute rankings regularly.


Or you can use Crono Gem, which would simplify this process. You can add this rule to an active job and run using Crono like so:

app/jobs/check_merit_rules_job.rb

class CheckMeritRankRulesJob < ActiveJob::Base
  def perform
    ActiveRecord::Base.connection_pool.with_connection do
     Merit::RankRules.new.check_rank_rules
    end
  end
end

config/cronotab.rb

Crono.perform(CheckMeritRankRulesJob).every 5.minutes #configure time

Note: If you are using Crono make sure the ActiveJob perform block doesn't take any arguments.(Merit doesn't need arguments anyway)

The rankings are ran on the a whole database scope and not only on some entries, and because they tend to need more information/computing that would take too long to compute as part of an HTTP request.


Background job for awarding Badges/Point

If you configure merit to not check badge/point rules on each request (checks_on_each_request) you'll need to check them in the background. The configuration for this is available in merit initializer file config/initializers/merit.rb

Behind the scenes, merit uses an after_filter on every meritable controller action and logs it into merit_actions table which makes it flexible to process Badge/Point rules later. You can read related code here L10

The call for checking unprocessed jobs is:

Merit::Action.check_unprocessed

Therefore, it makes it very flexible to run merit rules through a background job. Here is how you can configure Merit to use a background job (Same as rankings)

app/jobs/check_unprocessed_merit_rules_job.rb

class CheckUnprocessedMeritRulesJob < ActiveJob::Base
  def perform
    ActiveRecord::Base.connection_pool.with_connection do
     Merit::Action.check_unprocessed
    end
  end
end

config/cronotab.rb

Crono.perform(CheckUnprocessedMeritRulesJob).every 5.minutes #configure time as it fits your app needs

A little tip on performance: Use redis sorted sets to store points and rankings for each user and whenever ranking/points updates after computation use redis pub/sub to push updates in realtime without compromising performance.