sidekiq-grouping 0.0.6 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.travis.yml +0 -1
- data/README.md +64 -10
- data/lib/sidekiq/grouping.rb +8 -8
- data/lib/sidekiq/grouping/actor.rb +1 -0
- data/lib/sidekiq/grouping/batch.rb +17 -11
- data/lib/sidekiq/grouping/config.rb +3 -3
- data/lib/sidekiq/grouping/middleware.rb +6 -2
- data/lib/sidekiq/grouping/supervisor.rb +7 -0
- data/lib/sidekiq/grouping/version.rb +1 -1
- data/spec/modules/batch_spec.rb +2 -2
- data/spec/spec_helper.rb +1 -0
- data/spec/support/test_workers.rb +7 -3
- metadata +3 -3
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: c53ede8cde6f7b04ee9b0ae343f988d564a62944
         | 
| 4 | 
            +
              data.tar.gz: 22864e990a6ffeaf86ac5ef169072b00d054ef5f
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: ea56db9c75826ec9fd2cb990ef9cd553049a5200464f3722954a53f0678f353b88ab2477be3ce9c031dc4951460eac4a34618e7dc41c9b6d306887ba2b4460a0
         | 
| 7 | 
            +
              data.tar.gz: 678f49766262a89976638afae0a47c91e1361b2aeaf80a82a5e0f129019e9f6f76c80b6f8f378774adbc65780eaa8b7f6249132a5a4e733d329c6b1835534757
         | 
    
        data/.travis.yml
    CHANGED
    
    
    
        data/README.md
    CHANGED
    
    | @@ -1,14 +1,16 @@ | |
| 1 1 | 
             
            # Sidekiq::Grouping
         | 
| 2 2 |  | 
| 3 | 
            -
             | 
| 3 | 
            +
            <a href="https://evilmartians.com/?utm_source=sidekiq-grouping-gem">
         | 
| 4 | 
            +
            <img src="https://evilmartians.com/badges/sponsored-by-evil-martians.svg" alt="Sponsored by Evil Martians" width="236" height="54">
         | 
| 5 | 
            +
            </a>
         | 
| 4 6 |  | 
| 5 | 
            -
            Allows  | 
| 7 | 
            +
            Allows to combine similar sidekiq jobs into groups to process them at once.
         | 
| 6 8 |  | 
| 7 9 | 
             
            Useful for:
         | 
| 8 10 | 
             
            * Grouping asynchronous API index calls into bulks for bulk updating/indexing.
         | 
| 9 11 | 
             
            * Periodical batch updating of recently changing database counters.
         | 
| 10 12 |  | 
| 11 | 
            -
             | 
| 13 | 
            +
            *NOTE:* As of 1.0 `batch_size` renamed to `batch_flush_size`.
         | 
| 12 14 |  | 
| 13 15 | 
             
            ## Usage
         | 
| 14 16 |  | 
| @@ -19,9 +21,9 @@ class ElasticBulkIndexWorker | |
| 19 21 | 
             
              include Sidekiq::Worker
         | 
| 20 22 |  | 
| 21 23 | 
             
              sidekiq_options(
         | 
| 22 | 
            -
                queue: : | 
| 23 | 
            -
                 | 
| 24 | 
            -
                batch_flush_interval: 60, #  | 
| 24 | 
            +
                queue: :elasic_bulks,
         | 
| 25 | 
            +
                batch_flush_size: 30,     # Jobs will be combined when queue size exceeds 30
         | 
| 26 | 
            +
                batch_flush_interval: 60, # Jobs will be combined every 60 seconds
         | 
| 25 27 | 
             
                retry: 5
         | 
| 26 28 | 
             
              )
         | 
| 27 29 |  | 
| @@ -35,13 +37,15 @@ end | |
| 35 37 | 
             
            Perform a jobs:
         | 
| 36 38 |  | 
| 37 39 | 
             
            ```ruby
         | 
| 40 | 
            +
            # At least 30 times
         | 
| 41 | 
            +
             | 
| 38 42 | 
             
            ElasticBulkIndexWorker.perform_async({ delete: { _index: 'test', _id: 5, _type: 'user' } })
         | 
| 39 43 | 
             
            ElasticBulkIndexWorker.perform_async({ delete: { _index: 'test', _id: 6, _type: 'user' } })
         | 
| 40 44 | 
             
            ElasticBulkIndexWorker.perform_async({ delete: { _index: 'test', _id: 7, _type: 'user' } })
         | 
| 41 45 | 
             
            ...
         | 
| 42 46 | 
             
            ```
         | 
| 43 47 |  | 
| 44 | 
            -
            This jobs will be grouped into  | 
| 48 | 
            +
            This jobs will be grouped into the single job with the single argument:
         | 
| 45 49 |  | 
| 46 50 | 
             
            ```ruby
         | 
| 47 51 | 
             
            [
         | 
| @@ -52,7 +56,58 @@ This jobs will be grouped into a single job which will be performed with the sin | |
| 52 56 | 
             
            ]
         | 
| 53 57 | 
             
            ```
         | 
| 54 58 |  | 
| 55 | 
            -
             | 
| 59 | 
            +
            ## Control grouping
         | 
| 60 | 
            +
             | 
| 61 | 
            +
            - If `batch_flush_size` option is set - grouping will be performed when batched queue size exceeds this value or `Sidekiq::Grouping::Config.max_batch_size` (1000 by default).
         | 
| 62 | 
            +
            - If `batch_flush_interval` option is set - grouping will be performed every given interval.
         | 
| 63 | 
            +
            - If both are set - grouping will be performed when first condition become true. For example, if `batch_flush_interval` is set to 60 seconds and `batch_flush_size` is set to 5 - group task will be enqueued even if just 3 jobs are in the queue at the end of the minute. In the other hand, if 5 jobs were enqueued during 10 seconds - they will be grouped and enqueued immediately.
         | 
| 64 | 
            +
             | 
| 65 | 
            +
            ## Options
         | 
| 66 | 
            +
             | 
| 67 | 
            +
            - `batch_unique` prevents enqueue of jobs with identical arguments.
         | 
| 68 | 
            +
             | 
| 69 | 
            +
              ```ruby
         | 
| 70 | 
            +
              class FooWorker
         | 
| 71 | 
            +
                include Sidekiq::Worker
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                sidekiq_options batch_flush_interval: 10, batch_unique: true
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                def perform(n)
         | 
| 76 | 
            +
                  puts n
         | 
| 77 | 
            +
                end
         | 
| 78 | 
            +
              end
         | 
| 79 | 
            +
             | 
| 80 | 
            +
              FooWorker.perform_async(1)
         | 
| 81 | 
            +
              FooWorker.perform_async(1)
         | 
| 82 | 
            +
              FooWorker.perform_async(2)
         | 
| 83 | 
            +
              FooWorker.perform_async(2)
         | 
| 84 | 
            +
             | 
| 85 | 
            +
              # => [[1], [2]]
         | 
| 86 | 
            +
              ```
         | 
| 87 | 
            +
             | 
| 88 | 
            +
            - `batch_size` is used to control single group size.
         | 
| 89 | 
            +
             | 
| 90 | 
            +
              ```ruby
         | 
| 91 | 
            +
              class FooWorker
         | 
| 92 | 
            +
                include Sidekiq::Worker
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                sidekiq_options batch_flush_size: 5, batch_size: 2
         | 
| 95 | 
            +
             | 
| 96 | 
            +
                def perform(n)
         | 
| 97 | 
            +
                  puts n
         | 
| 98 | 
            +
                end
         | 
| 99 | 
            +
              end
         | 
| 100 | 
            +
             | 
| 101 | 
            +
              FooWorker.perform_async(1)
         | 
| 102 | 
            +
              FooWorker.perform_async(2)
         | 
| 103 | 
            +
              FooWorker.perform_async(3)
         | 
| 104 | 
            +
              FooWorker.perform_async(4)
         | 
| 105 | 
            +
              FooWorker.perform_async(5)
         | 
| 106 | 
            +
             | 
| 107 | 
            +
              # => [[1], [2]]
         | 
| 108 | 
            +
              # => [[3], [4]]
         | 
| 109 | 
            +
              # => [[5]]
         | 
| 110 | 
            +
              ```
         | 
| 56 111 |  | 
| 57 112 | 
             
            ## Web UI
         | 
| 58 113 |  | 
| @@ -69,13 +124,12 @@ require "sidekiq/grouping/web" | |
| 69 124 | 
             
            ```ruby
         | 
| 70 125 | 
             
            Sidekiq::Grouping::Config.poll_interval = 5     # Amount of time between polling batches
         | 
| 71 126 | 
             
            Sidekiq::Grouping::Config.max_batch_size = 5000 # Maximum batch size allowed
         | 
| 72 | 
            -
            Sidekiq::Grouping::Config.lock_ttl = 1          #  | 
| 127 | 
            +
            Sidekiq::Grouping::Config.lock_ttl = 1          # Batch queue flush lock timeout job enqueues
         | 
| 73 128 | 
             
            ```
         | 
| 74 129 |  | 
| 75 130 | 
             
            ## TODO
         | 
| 76 131 |  | 
| 77 132 | 
             
            1. Add support redis_pool option.
         | 
| 78 | 
            -
            2. Make able to work together with sidekiq-unique-jobs.
         | 
| 79 133 |  | 
| 80 134 | 
             
            ## Installation
         | 
| 81 135 |  | 
    
        data/lib/sidekiq/grouping.rb
    CHANGED
    
    | @@ -1,18 +1,18 @@ | |
| 1 1 | 
             
            require 'active_support/core_ext/string'
         | 
| 2 2 | 
             
            require 'active_support/configurable'
         | 
| 3 3 | 
             
            require 'active_support/core_ext/numeric/time'
         | 
| 4 | 
            -
             | 
| 5 | 
            -
            require 'sidekiq/grouping/config'
         | 
| 6 | 
            -
            require 'sidekiq/grouping/redis'
         | 
| 7 | 
            -
            require 'sidekiq/grouping/batch'
         | 
| 8 | 
            -
            require 'sidekiq/grouping/middleware'
         | 
| 9 | 
            -
            require 'sidekiq/grouping/logging'
         | 
| 10 | 
            -
            require 'sidekiq/grouping/actor'
         | 
| 11 | 
            -
            require 'sidekiq/grouping/supervisor'
         | 
| 12 4 | 
             
            require 'sidekiq/grouping/version'
         | 
| 13 5 |  | 
| 14 6 | 
             
            module Sidekiq
         | 
| 15 7 | 
             
              module Grouping
         | 
| 8 | 
            +
                autoload :Config, 'sidekiq/grouping/config'
         | 
| 9 | 
            +
                autoload :Redis, 'sidekiq/grouping/redis'
         | 
| 10 | 
            +
                autoload :Batch, 'sidekiq/grouping/batch'
         | 
| 11 | 
            +
                autoload :Middleware, 'sidekiq/grouping/middleware'
         | 
| 12 | 
            +
                autoload :Logging, 'sidekiq/grouping/logging'
         | 
| 13 | 
            +
                autoload :Actor, 'sidekiq/grouping/actor'
         | 
| 14 | 
            +
                autoload :Supervisor, 'sidekiq/grouping/supervisor'
         | 
| 15 | 
            +
             | 
| 16 16 | 
             
                class << self
         | 
| 17 17 | 
             
                  attr_writer :logger
         | 
| 18 18 |  | 
| @@ -27,25 +27,32 @@ module Sidekiq | |
| 27 27 |  | 
| 28 28 | 
             
                  def chunk_size
         | 
| 29 29 | 
             
                    worker_class_options['batch_size'] ||
         | 
| 30 | 
            -
             | 
| 30 | 
            +
                      Sidekiq::Grouping::Config.max_batch_size
         | 
| 31 | 
            +
                  end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                  def pluck_size
         | 
| 34 | 
            +
                    worker_class_options['batch_flush_size'] ||
         | 
| 35 | 
            +
                      Sidekiq::Grouping::Config.max_batch_size
         | 
| 31 36 | 
             
                  end
         | 
| 32 37 |  | 
| 33 38 | 
             
                  def pluck
         | 
| 34 39 | 
             
                    if @redis.lock(@name)
         | 
| 35 | 
            -
                      @redis.pluck(@name,  | 
| 40 | 
            +
                      @redis.pluck(@name, pluck_size).map { |value| JSON.parse(value) }
         | 
| 36 41 | 
             
                    end
         | 
| 37 42 | 
             
                  end
         | 
| 38 43 |  | 
| 39 44 | 
             
                  def flush
         | 
| 40 45 | 
             
                    chunk = pluck
         | 
| 41 | 
            -
                     | 
| 42 | 
            -
             | 
| 46 | 
            +
                    return unless chunk
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                    chunk.each_slice(chunk_size) do |subchunk|
         | 
| 43 49 | 
             
                      Sidekiq::Client.push(
         | 
| 44 50 | 
             
                        'class' => @worker_class,
         | 
| 45 51 | 
             
                        'queue' => @queue,
         | 
| 46 | 
            -
                        'args' => [true,  | 
| 52 | 
            +
                        'args' => [true, subchunk]
         | 
| 47 53 | 
             
                      )
         | 
| 48 54 | 
             
                    end
         | 
| 55 | 
            +
                    set_current_time_as_last
         | 
| 49 56 | 
             
                  end
         | 
| 50 57 |  | 
| 51 58 | 
             
                  def worker_class_constant
         | 
| @@ -79,9 +86,11 @@ module Sidekiq | |
| 79 86 | 
             
                  end
         | 
| 80 87 |  | 
| 81 88 | 
             
                  private
         | 
| 89 | 
            +
             | 
| 82 90 | 
             
                  def could_flush_on_overflow?
         | 
| 83 | 
            -
                     | 
| 84 | 
            -
                     | 
| 91 | 
            +
                    return true if size >= Sidekiq::Grouping::Config.max_batch_size
         | 
| 92 | 
            +
                    worker_class_options['batch_flush_size'] &&
         | 
| 93 | 
            +
                      size >= worker_class_options['batch_flush_size']
         | 
| 85 94 | 
             
                  end
         | 
| 86 95 |  | 
| 87 96 | 
             
                  def could_flush_on_time?
         | 
| @@ -94,9 +103,7 @@ module Sidekiq | |
| 94 103 | 
             
                      set_current_time_as_last
         | 
| 95 104 | 
             
                      false
         | 
| 96 105 | 
             
                    else
         | 
| 97 | 
            -
                      if next_time
         | 
| 98 | 
            -
                        next_time < Time.now
         | 
| 99 | 
            -
                      end
         | 
| 106 | 
            +
                      next_time < Time.now if next_time
         | 
| 100 107 | 
             
                    end
         | 
| 101 108 | 
             
                  end
         | 
| 102 109 |  | 
| @@ -122,7 +129,6 @@ module Sidekiq | |
| 122 129 | 
             
                      [klass.classify, queue]
         | 
| 123 130 | 
             
                    end
         | 
| 124 131 | 
             
                  end
         | 
| 125 | 
            -
             | 
| 126 132 | 
             
                end
         | 
| 127 133 | 
             
              end
         | 
| 128 134 | 
             
            end
         | 
| @@ -3,15 +3,15 @@ module Sidekiq | |
| 3 3 | 
             
                module Config
         | 
| 4 4 | 
             
                  include ActiveSupport::Configurable
         | 
| 5 5 |  | 
| 6 | 
            -
                  #  | 
| 6 | 
            +
                  # Queue size overflow check polling interval
         | 
| 7 7 | 
             
                  config_accessor :poll_interval
         | 
| 8 8 | 
             
                  self.config.poll_interval = 3
         | 
| 9 9 |  | 
| 10 10 | 
             
                  # Maximum batch size
         | 
| 11 11 | 
             
                  config_accessor :max_batch_size
         | 
| 12 | 
            -
                  self.config.max_batch_size =  | 
| 12 | 
            +
                  self.config.max_batch_size = 1000
         | 
| 13 13 |  | 
| 14 | 
            -
                  # Batch queue lock timeout | 
| 14 | 
            +
                  # Batch queue flush lock timeout
         | 
| 15 15 | 
             
                  config_accessor :lock_ttl
         | 
| 16 16 | 
             
                  self.config.lock_ttl = 1
         | 
| 17 17 | 
             
                end
         | 
| @@ -6,7 +6,7 @@ module Sidekiq | |
| 6 6 | 
             
                    options = worker_class.get_sidekiq_options
         | 
| 7 7 |  | 
| 8 8 | 
             
                    batch =
         | 
| 9 | 
            -
                      options.keys.include?(' | 
| 9 | 
            +
                      options.keys.include?('batch_flush_size') ||
         | 
| 10 10 | 
             
                      options.keys.include?('batch_flush_interval')
         | 
| 11 11 |  | 
| 12 12 | 
             
                    passthrough =
         | 
| @@ -25,8 +25,12 @@ module Sidekiq | |
| 25 25 | 
             
                  end
         | 
| 26 26 |  | 
| 27 27 | 
             
                  private
         | 
| 28 | 
            +
             | 
| 28 29 | 
             
                  def add_to_batch(worker_class, queue, msg, redis_pool = nil)
         | 
| 29 | 
            -
                    Sidekiq::Grouping::Batch | 
| 30 | 
            +
                    Sidekiq::Grouping::Batch
         | 
| 31 | 
            +
                      .new(worker_class.name, queue, redis_pool)
         | 
| 32 | 
            +
                      .add(msg['args'])
         | 
| 33 | 
            +
             | 
| 30 34 | 
             
                    nil
         | 
| 31 35 | 
             
                  end
         | 
| 32 36 | 
             
                end
         | 
| @@ -4,10 +4,17 @@ module Sidekiq | |
| 4 4 | 
             
                  class << self
         | 
| 5 5 | 
             
                    include Sidekiq::Grouping::Logging
         | 
| 6 6 |  | 
| 7 | 
            +
                    if Celluloid::VERSION >= '0.17'
         | 
| 8 | 
            +
                    def run!
         | 
| 9 | 
            +
                      info 'Sidekiq::Grouping starts supervision'
         | 
| 10 | 
            +
                      Sidekiq::Grouping::Actor.supervise as: :sidekiq_grouping
         | 
| 11 | 
            +
                    end
         | 
| 12 | 
            +
                    else
         | 
| 7 13 | 
             
                    def run!
         | 
| 8 14 | 
             
                      info 'Sidekiq::Grouping starts supervision'
         | 
| 9 15 | 
             
                      Sidekiq::Grouping::Actor.supervise_as(:sidekiq_grouping)
         | 
| 10 16 | 
             
                    end
         | 
| 17 | 
            +
                    end
         | 
| 11 18 | 
             
                  end
         | 
| 12 19 | 
             
                end
         | 
| 13 20 | 
             
              end
         | 
    
        data/spec/modules/batch_spec.rb
    CHANGED
    
    | @@ -65,9 +65,9 @@ describe Sidekiq::Grouping::Batch do | |
| 65 65 | 
             
                  batch = subject.new(BatchedSizeWorker.name, 'batched_size')
         | 
| 66 66 |  | 
| 67 67 | 
             
                  expect(batch.could_flush?).to be_falsy
         | 
| 68 | 
            -
                  10.times { BatchedSizeWorker.perform_async( | 
| 68 | 
            +
                  10.times { |n| BatchedSizeWorker.perform_async("bar#{n}") }
         | 
| 69 69 | 
             
                  batch.flush
         | 
| 70 | 
            -
                  expect(BatchedSizeWorker).to have_enqueued_job([[" | 
| 70 | 
            +
                  expect(BatchedSizeWorker).to have_enqueued_job([["bar0"], ["bar1"]])
         | 
| 71 71 | 
             
                  expect(batch.size).to eq(7)
         | 
| 72 72 | 
             
                end
         | 
| 73 73 | 
             
              end
         | 
    
        data/spec/spec_helper.rb
    CHANGED
    
    
| @@ -8,7 +8,7 @@ end | |
| 8 8 | 
             
            class BatchedSizeWorker
         | 
| 9 9 | 
             
              include Sidekiq::Worker
         | 
| 10 10 |  | 
| 11 | 
            -
              sidekiq_options queue: :batched_size, batch_size:  | 
| 11 | 
            +
              sidekiq_options queue: :batched_size, batch_flush_size: 3, batch_size: 2
         | 
| 12 12 |  | 
| 13 13 | 
             
              def perform(foo)
         | 
| 14 14 | 
             
              end
         | 
| @@ -26,7 +26,9 @@ end | |
| 26 26 | 
             
            class BatchedBothWorker
         | 
| 27 27 | 
             
              include Sidekiq::Worker
         | 
| 28 28 |  | 
| 29 | 
            -
              sidekiq_options | 
| 29 | 
            +
              sidekiq_options(
         | 
| 30 | 
            +
                queue: :batched_both, batch_flush_interval: 3600, batch_flush_size: 3
         | 
| 31 | 
            +
              )
         | 
| 30 32 |  | 
| 31 33 | 
             
              def perform(foo)
         | 
| 32 34 | 
             
              end
         | 
| @@ -35,7 +37,9 @@ end | |
| 35 37 | 
             
            class BatchedUniqueArgsWorker
         | 
| 36 38 | 
             
              include Sidekiq::Worker
         | 
| 37 39 |  | 
| 38 | 
            -
              sidekiq_options | 
| 40 | 
            +
              sidekiq_options(
         | 
| 41 | 
            +
                queue: :batched_unique_args, batch_flush_size: 3, batch_unique: true
         | 
| 42 | 
            +
              )
         | 
| 39 43 |  | 
| 40 44 | 
             
              def perform(foo)
         | 
| 41 45 | 
             
              end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: sidekiq-grouping
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version:  | 
| 4 | 
            +
              version: 1.0.1
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Victor Sokolov
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2015- | 
| 11 | 
            +
            date: 2015-11-11 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: bundler
         | 
| @@ -186,7 +186,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 186 186 | 
             
                  version: '0'
         | 
| 187 187 | 
             
            requirements: []
         | 
| 188 188 | 
             
            rubyforge_project: 
         | 
| 189 | 
            -
            rubygems_version: 2.4. | 
| 189 | 
            +
            rubygems_version: 2.4.8
         | 
| 190 190 | 
             
            signing_key: 
         | 
| 191 191 | 
             
            specification_version: 4
         | 
| 192 192 | 
             
            summary: Allows identical sidekiq jobs to be processed with a single background call
         |