Commit a7431d97424fcbc61b0f4a47bcb055ad6bd5b522

Authored by Luke Baker
1 parent 92dd57ad

generate 1000 prompts at once

only generate prompts if cache is less than 90% full
app/models/question.rb
... ... @@ -80,26 +80,29 @@ class Question < ActiveRecord::Base
80 80 end
81 81  
82 82 # adapted from ruby cookbook(2006): section 5-11
83   - def catchup_choose_prompt
  83 + def catchup_choose_prompt(num=1000)
84 84 weighted = catchup_prompts_weights
85 85 # Rand returns a number from 0 - 1, so weighted needs to be normalized
86   - prompt = nil
87   -
88   - until prompt && prompt.active?
89   - target = rand
90   - left_choice_id = right_choice_id = nil
91   -
92   - weighted.each do |item, weight|
93   - if target <= weight
94   - left_choice_id, right_choice_id = item.split(", ")
95   - break
  86 + generated_prompts = []
  87 +
  88 + num.times do
  89 + prompt = nil
  90 + until prompt && prompt.active?
  91 + target = rand
  92 + left_choice_id = right_choice_id = nil
  93 +
  94 + weighted.each do |item, weight|
  95 + if target <= weight
  96 + left_choice_id, right_choice_id = item.split(", ")
  97 + break
  98 + end
  99 + target -= weight
96 100 end
97   - target -= weight
  101 + prompt = prompts.find_or_create_by_left_choice_id_and_right_choice_id(left_choice_id, right_choice_id, :include => [{ :left_choice => :item }, { :right_choice => :item }])
98 102 end
99   - prompt = prompts.find_or_create_by_left_choice_id_and_right_choice_id(left_choice_id, right_choice_id, :include => [{ :left_choice => :item }, { :right_choice => :item }])
  103 + generated_prompts.push prompt
100 104 end
101   - # check if prompt has two active choices here, maybe we can set this on the prompt level too?
102   - prompt
  105 + generated_prompts
103 106 end
104 107  
105 108  
... ... @@ -472,9 +475,18 @@ class Question &lt; ActiveRecord::Base
472 475 end
473 476  
474 477 def add_prompt_to_queue
475   - prompt = self.catchup_choose_prompt
476   - $redis.rpush(self.pq_key, prompt.id)
477   - prompt
  478 + num_prompts = 1000
  479 + # if less than 90% full, regenerate prompts
  480 + if $redis.llen(self.pq_key) < num_prompts * 0.9
  481 + prompts = self.catchup_choose_prompt(num_prompts)
  482 + # clear list
  483 + $redis.ltrim(self.pq_key, 0, 0)
  484 + $redis.lpop(self.pq_key)
  485 + prompts.each do |prompt|
  486 + $redis.rpush(self.pq_key, prompt.id)
  487 + end
  488 + return prompts
  489 + end
478 490 end
479 491  
480 492 def pop_prompt_queue
... ...
lib/tasks/test_api.rake
... ... @@ -39,7 +39,7 @@ namespace :test_api do
39 39 1000.times do |n|
40 40 puts "#{n} votes completed" if n % 100 == 0
41 41 question = Question.find(214) # test question change as needed
42   - @prompt = question.catchup_choose_prompt
  42 + @prompt = question.catchup_choose_prompt(1).first
43 43 @appearance = current_user.record_appearance(current_user.default_visitor, @prompt)
44 44  
45 45 direction = (rand(2) == 0) ? "left" : "right"
... ...
spec/models/question_spec.rb
... ... @@ -55,7 +55,7 @@ describe Question do
55 55 end
56 56  
57 57 it "should choose an active prompt using catchup algorithm" do
58   - prompt = @question.catchup_choose_prompt
  58 + prompt = @question.catchup_choose_prompt(1).first
59 59 prompt.active?.should == true
60 60 end
61 61  
... ... @@ -242,7 +242,7 @@ describe Question do
242 242 # Sanity check
243 243 @catchup_q.choices.size.should == 100
244 244  
245   - prompt = @catchup_q.catchup_choose_prompt
  245 + prompt = @catchup_q.catchup_choose_prompt(1).first
246 246 prompt.active?.should == true
247 247 end
248 248  
... ... @@ -282,36 +282,10 @@ describe Question do
282 282 prompt.should_not == nil
283 283 prompt.active?.should == true
284 284 end
285   - it "should return prompts from the queue in FIFO order" do
286   - @catchup_q.clear_prompt_queue
287   - @catchup_q.pop_prompt_queue.should == nil
288   -
289   - prompt1 = @catchup_q.add_prompt_to_queue
290   - prompt2 = @catchup_q.add_prompt_to_queue
291   - prompt3 = @catchup_q.add_prompt_to_queue
292   -
293   - prompt_1 = @catchup_q.pop_prompt_queue
294   - prompt_2 = @catchup_q.pop_prompt_queue
295   - prompt_3 = @catchup_q.pop_prompt_queue
296   -
297   -
298   - prompt_1.should == prompt1
299   - prompt_2.should == prompt2
300   - prompt_3.should == prompt3
301   -
302   - # there is a small probability that the catchup algorithm
303   - # choose two prompts that are indeed equal
304   - prompt_1.should_not == prompt_2
305   - prompt_1.should_not == prompt_3
306   - prompt_2.should_not == prompt_3
307   -
308   -
309   - @catchup_q.pop_prompt_queue.should == nil
310   - end
311 285 it "should not return prompts from queue that are deactivated" do
312 286 @catchup_q.clear_prompt_queue
313 287 @catchup_q.pop_prompt_queue.should == nil
314   - prompt1 = @catchup_q.add_prompt_to_queue
  288 + prompt1 = @catchup_q.add_prompt_to_queue.first
315 289  
316 290 prompt = Prompt.find(prompt1)
317 291 prompt.left_choice.deactivate!
... ...