From fa8f3f1d10725be47f45830926f8d633b58ad33d Mon Sep 17 00:00:00 2001 From: John Hawthorn <john.hawthorn@gmail.com> Date: Thu, 15 Feb 2018 12:24:13 -0800 Subject: [PATCH 1/2] Don't use association in batch_builder Previously this was building codes on the association and then relying on the autosave behaviour to save the new records when save was called on the Promotion. It's simpler to just explicitly create them. --- .../models/spree/promotion_code/batch_builder.rb | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/core/app/models/spree/promotion_code/batch_builder.rb b/core/app/models/spree/promotion_code/batch_builder.rb index 0578b825fe5..42de084d8e2 100644 --- a/core/app/models/spree/promotion_code/batch_builder.rb +++ b/core/app/models/spree/promotion_code/batch_builder.rb @@ -37,16 +37,13 @@ def generate_random_codes codes_for_current_batch += get_unique_codes(new_codes) end - codes_for_current_batch.map do |value| - promotion.codes.build(value: value, promotion_code_batch: promotion_code_batch) + codes_for_current_batch.each do |value| + Spree::PromotionCode.create!( + value: value, + promotion: promotion, + promotion_code_batch: promotion_code_batch + ) end - - promotion.save! - - # We have to reload the promotion because otherwise all promotion codes - # we are creating will remain in memory. Doing a reload will remove all - # codes from memory. - promotion.reload end end From c9051584d5821a9072009c36b34c5f3aaddf2f3c Mon Sep 17 00:00:00 2001 From: John Hawthorn <john.hawthorn@gmail.com> Date: Thu, 15 Feb 2018 12:28:53 -0800 Subject: [PATCH 2/2] Generate correct number of codes in BatchBuilder Previously, due to a bug in the inner loop, BatchBuilder could generate more codes than were requested. This removes the inner loop in favour of a single, smarter outer loop. Instead of always creating exactly batch_size new codes, we now create up to batch_size new codes. On each loop we try to generate batch_size new potential codes and only save the ones which are unique. This should result in fewer selects in scenarios where there is contention over codes. Though this is entire system is not well suited for there to be many conflicts. --- .../models/spree/promotion_code/batch_builder.rb | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/core/app/models/spree/promotion_code/batch_builder.rb b/core/app/models/spree/promotion_code/batch_builder.rb index 42de084d8e2..a13c3f22792 100644 --- a/core/app/models/spree/promotion_code/batch_builder.rb +++ b/core/app/models/spree/promotion_code/batch_builder.rb @@ -26,16 +26,13 @@ def build_promotion_codes private def generate_random_codes - total_batches = (number_of_codes.to_f / self.class.batch_size).ceil + created_codes = 0 - total_batches.times do |i| - codes_for_current_batch = Set.new - codes_to_generate = [self.class.batch_size, number_of_codes - i * batch_size].min + while created_codes < number_of_codes + max_codes_to_generate = [self.class.batch_size, number_of_codes - created_codes].min - while codes_for_current_batch.size < codes_to_generate - new_codes = Array.new(codes_to_generate) { generate_random_code }.to_set - codes_for_current_batch += get_unique_codes(new_codes) - end + new_codes = Array.new(max_codes_to_generate) { generate_random_code }.uniq + codes_for_current_batch = get_unique_codes(new_codes) codes_for_current_batch.each do |value| Spree::PromotionCode.create!( @@ -44,6 +41,7 @@ def generate_random_codes promotion_code_batch: promotion_code_batch ) end + created_codes += codes_for_current_batch.size end end