From 46ba67eb2b514c47f5b3de7e4ddffaf4ab2d30d9 Mon Sep 17 00:00:00 2001 From: Victor Costa Date: Mon, 31 Aug 2015 15:18:35 -0300 Subject: [PATCH] Process ranking in an async job --- lib/proposals_discussion_plugin.rb | 3 +++ lib/proposals_discussion_plugin/api.rb | 10 +++------- lib/proposals_discussion_plugin/ranking_job.rb | 36 ++++++++++++++++++++++++++++++++++++ test/unit/api_test.rb | 2 ++ test/unit/ranking_job_test.rb | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 100 insertions(+), 7 deletions(-) create mode 100644 lib/proposals_discussion_plugin/ranking_job.rb create mode 100644 test/unit/ranking_job_test.rb diff --git a/lib/proposals_discussion_plugin.rb b/lib/proposals_discussion_plugin.rb index bc6e45e..3945539 100644 --- a/lib/proposals_discussion_plugin.rb +++ b/lib/proposals_discussion_plugin.rb @@ -52,4 +52,7 @@ class ProposalsDiscussionPlugin < Noosfero::Plugin [ProposalsDiscussionPlugin::API] end + # schedule ranking job in initialization process + ProposalsDiscussionPlugin::RankingJob.new.schedule + end diff --git a/lib/proposals_discussion_plugin/api.rb b/lib/proposals_discussion_plugin/api.rb index ec4b0e4..e0dd4d3 100644 --- a/lib/proposals_discussion_plugin/api.rb +++ b/lib/proposals_discussion_plugin/api.rb @@ -5,13 +5,9 @@ class ProposalsDiscussionPlugin::API < Grape::API paginate per_page: 10, max_per_page: 20 get ':id/ranking' do article = find_article(environment.articles, params[:id]) - ranking = Rails.cache.fetch("#{article.cache_key}/proposals_ranking", expires_in: 30.minutes) do - #FIXME call update_ranking in an async job - article.update_ranking - {:proposals => article.ranking, :updated_at => DateTime.now} - end - ranking[:proposals] = paginate ranking[:proposals] - ranking + current_page = paginate(article.ranking) + #FIXME find a better way to get updated_at date + {:proposals => current_page, :updated_at => current_page.blank? ? DateTime.now : current_page.first.updated_at} end post ':id/propose' do diff --git a/lib/proposals_discussion_plugin/ranking_job.rb b/lib/proposals_discussion_plugin/ranking_job.rb new file mode 100644 index 0000000..e3ab749 --- /dev/null +++ b/lib/proposals_discussion_plugin/ranking_job.rb @@ -0,0 +1,36 @@ +class ProposalsDiscussionPlugin::RankingJob + + def perform + ProposalsDiscussionPlugin::Topic.find_each do |topic| + ProposalsDiscussionPlugin::RankingJob::TopicRankingJob.new(topic.id).schedule + end + schedule(30.minutes.from_now) + end + + def schedule(run_at = nil) + Delayed::Job.enqueue(self, {:run_at => run_at}) unless self.class.find_job.exists? + end + + def self.find_job + Delayed::Job.by_handler("--- !ruby/object:ProposalsDiscussionPlugin::RankingJob {}\n") + end + + + class TopicRankingJob < Struct.new(:topic_id) + + def perform + topic = ProposalsDiscussionPlugin::Topic.find_by_id(topic_id) + topic.update_ranking if topic.present? + end + + def schedule + Delayed::Job.enqueue(self) unless find_job.exists? + end + + def find_job + Delayed::Job.by_handler("--- !ruby/struct:ProposalsDiscussionPlugin::RankingJob::TopicRankingJob\ntopic_id: #{topic_id}\n") + end + + end + +end diff --git a/test/unit/api_test.rb b/test/unit/api_test.rb index c43049b..6aa0b6c 100644 --- a/test/unit/api_test.rb +++ b/test/unit/api_test.rb @@ -30,10 +30,12 @@ class APITest < ActiveSupport::TestCase 2.times { Vote.create!(:voteable => proposal3, :voter => nil, :vote => 1) } proposal1.update_attribute(:hits, 5) + process_delayed_job_queue get "/api/v1/proposals_discussion_plugin/#{topic.id}/ranking?#{params.to_query}" json = JSON.parse(last_response.body) assert_equal [proposal2.abstract, proposal3.abstract, proposal1.abstract], json['proposals'].map {|p| p['abstract']} + assert json['updated_at'].to_datetime <= Time.now end should 'suggest article children' do diff --git a/test/unit/ranking_job_test.rb b/test/unit/ranking_job_test.rb new file mode 100644 index 0000000..f926a70 --- /dev/null +++ b/test/unit/ranking_job_test.rb @@ -0,0 +1,56 @@ +require_relative '../test_helper' + +class RankingJobTest < ActiveSupport::TestCase + + def setup + @job = ProposalsDiscussionPlugin::RankingJob.new + @topic = fast_create(ProposalsDiscussionPlugin::Topic) + @proposal = fast_create(ProposalsDiscussionPlugin::Proposal, :parent_id => topic.id) + end + + attr_accessor :job, :topic, :proposal + + should 'create ranking job in initialization' do + assert job.class.find_job.exists? + end + + should 'do not create duplicated ranking job' do + job.schedule + job.schedule + assert_equal 1, job.class.find_job.count + end + + should 'schedule topic jobs when performed' do + job.perform + assert ProposalsDiscussionPlugin::RankingJob::TopicRankingJob.new(topic.id).find_job.exists? + end + + should 'reschedule job when performed' do + process_delayed_job_queue + job.perform + new_job = job.class.find_job.first + assert new_job.present? + assert new_job.run_at > 20.minutes.from_now + end + + should 'schedule topic job' do + topic_job = ProposalsDiscussionPlugin::RankingJob::TopicRankingJob.new(topic.id) + topic_job.schedule + assert topic_job.find_job.exists? + end + + should 'do not schedule duplicated topic job' do + topic_job = ProposalsDiscussionPlugin::RankingJob::TopicRankingJob.new(topic.id) + topic_job.schedule + topic_job.schedule + assert_equal 1, topic_job.find_job.count + end + + should 'perform topic job' do + job.schedule + assert_equal 0, topic.ranking.count + process_delayed_job_queue + assert_equal 1, topic.ranking.count + end + +end -- libgit2 0.21.2