semian 0.25.4 → 0.26.5
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/lib/semian/instrumentable.rb +11 -9
 - data/lib/semian/simple_integer.rb +22 -6
 - data/lib/semian/simple_sliding_window.rb +40 -47
 - data/lib/semian/version.rb +1 -1
 - data/lib/semian.rb +37 -24
 - metadata +1 -1
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA256:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 20f2ab860d074c5420db9d4a5ec675307fdf046c4ad06d3aab227273b7a3716c
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 25e865fa1a72948765a572a20ccfbdea783c4940fd245bf18f281af8a2351f54
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: f8dbe833518cadd4083cb104554add1f1e0b506d02f92b8b55dbc763ff822e5e5fdf22633b3de415fde54ba56780c5ea2e2aae88bd08d7367d5fa5e10ea58d33
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: a126b289713f04a264a7a8e24e25fa1b7cd964477a22ec5f62696710c79abb9f6e73c74ef71ed77e7d05665d79ea67b53bc598d0c8b2a837eef8f8a75b608e71
         
     | 
| 
         @@ -1,14 +1,22 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
      
 3 
     | 
    
         
            +
            require "concurrent-ruby"
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
       3 
5 
     | 
    
         
             
            module Semian
         
     | 
| 
       4 
6 
     | 
    
         
             
              module Instrumentable
         
     | 
| 
      
 7 
     | 
    
         
            +
                SUBSCRIBERS = Concurrent::Map.new
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
       5 
9 
     | 
    
         
             
                def subscribe(name = rand, &block)
         
     | 
| 
       6 
     | 
    
         
            -
                   
     | 
| 
      
 10 
     | 
    
         
            +
                  SUBSCRIBERS[name] = block
         
     | 
| 
       7 
11 
     | 
    
         
             
                  name
         
     | 
| 
       8 
12 
     | 
    
         
             
                end
         
     | 
| 
       9 
13 
     | 
    
         | 
| 
       10 
14 
     | 
    
         
             
                def unsubscribe(name)
         
     | 
| 
       11 
     | 
    
         
            -
                   
     | 
| 
      
 15 
     | 
    
         
            +
                  SUBSCRIBERS.delete(name)
         
     | 
| 
      
 16 
     | 
    
         
            +
                end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                def subscribers
         
     | 
| 
      
 19 
     | 
    
         
            +
                  SUBSCRIBERS
         
     | 
| 
       12 
20 
     | 
    
         
             
                end
         
     | 
| 
       13 
21 
     | 
    
         | 
| 
       14 
22 
     | 
    
         
             
                # Args:
         
     | 
| 
         @@ -18,13 +26,7 @@ module Semian 
     | 
|
| 
       18 
26 
     | 
    
         
             
                #   adapter (string)
         
     | 
| 
       19 
27 
     | 
    
         
             
                #   payload (optional)
         
     | 
| 
       20 
28 
     | 
    
         
             
                def notify(*args)
         
     | 
| 
       21 
     | 
    
         
            -
                   
     | 
| 
       22 
     | 
    
         
            -
                end
         
     | 
| 
       23 
     | 
    
         
            -
             
     | 
| 
       24 
     | 
    
         
            -
                private
         
     | 
| 
       25 
     | 
    
         
            -
             
     | 
| 
       26 
     | 
    
         
            -
                def subscribers
         
     | 
| 
       27 
     | 
    
         
            -
                  @subscribers ||= {}
         
     | 
| 
      
 29 
     | 
    
         
            +
                  SUBSCRIBERS.values.each { |subscriber| subscriber.call(*args) }
         
     | 
| 
       28 
30 
     | 
    
         
             
                end
         
     | 
| 
       29 
31 
     | 
    
         
             
              end
         
     | 
| 
       30 
32 
     | 
    
         
             
            end
         
     | 
| 
         @@ -1,6 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            require "thread"
         
     | 
| 
      
 4 
     | 
    
         
            +
            require "concurrent"
         
     | 
| 
       4 
5 
     | 
    
         | 
| 
       5 
6 
     | 
    
         
             
            module Semian
         
     | 
| 
       6 
7 
     | 
    
         
             
              module Simple
         
     | 
| 
         @@ -26,14 +27,29 @@ module Semian 
     | 
|
| 
       26 
27 
     | 
    
         
             
              end
         
     | 
| 
       27 
28 
     | 
    
         | 
| 
       28 
29 
     | 
    
         
             
              module ThreadSafe
         
     | 
| 
       29 
     | 
    
         
            -
                class Integer 
     | 
| 
       30 
     | 
    
         
            -
                  def initialize 
     | 
| 
       31 
     | 
    
         
            -
                     
     | 
| 
       32 
     | 
    
         
            -
             
     | 
| 
      
 30 
     | 
    
         
            +
                class Integer
         
     | 
| 
      
 31 
     | 
    
         
            +
                  def initialize
         
     | 
| 
      
 32 
     | 
    
         
            +
                    @atom = Concurrent::AtomicFixnum.new(0)
         
     | 
| 
      
 33 
     | 
    
         
            +
                  end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                  def value
         
     | 
| 
      
 36 
     | 
    
         
            +
                    @atom.value
         
     | 
| 
       33 
37 
     | 
    
         
             
                  end
         
     | 
| 
       34 
38 
     | 
    
         | 
| 
       35 
     | 
    
         
            -
                  def  
     | 
| 
       36 
     | 
    
         
            -
                    @ 
     | 
| 
      
 39 
     | 
    
         
            +
                  def value=(new_value)
         
     | 
| 
      
 40 
     | 
    
         
            +
                    @atom.value = new_value
         
     | 
| 
      
 41 
     | 
    
         
            +
                  end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                  def increment(val = 1)
         
     | 
| 
      
 44 
     | 
    
         
            +
                    @atom.increment(val)
         
     | 
| 
      
 45 
     | 
    
         
            +
                  end
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                  def reset
         
     | 
| 
      
 48 
     | 
    
         
            +
                    @atom.value = 0
         
     | 
| 
      
 49 
     | 
    
         
            +
                  end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                  def destroy
         
     | 
| 
      
 52 
     | 
    
         
            +
                    reset
         
     | 
| 
       37 
53 
     | 
    
         
             
                  end
         
     | 
| 
       38 
54 
     | 
    
         
             
                end
         
     | 
| 
       39 
55 
     | 
    
         
             
              end
         
     | 
| 
         @@ -1,69 +1,62 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            require "thread"
         
     | 
| 
      
 4 
     | 
    
         
            +
            require "concurrent"
         
     | 
| 
       4 
5 
     | 
    
         | 
| 
       5 
6 
     | 
    
         
             
            module Semian
         
     | 
| 
       6 
     | 
    
         
            -
              module  
     | 
| 
       7 
     | 
    
         
            -
                 
     | 
| 
       8 
     | 
    
         
            -
                  extend Forwardable
         
     | 
| 
      
 7 
     | 
    
         
            +
              module SlidingWindowBehavior
         
     | 
| 
      
 8 
     | 
    
         
            +
                extend Forwardable
         
     | 
| 
       9 
9 
     | 
    
         | 
| 
       10 
     | 
    
         
            -
             
     | 
| 
       11 
     | 
    
         
            -
             
     | 
| 
      
 10 
     | 
    
         
            +
                def_delegators :@window, :size, :last, :empty?
         
     | 
| 
      
 11 
     | 
    
         
            +
                attr_reader :max_size
         
     | 
| 
       12 
12 
     | 
    
         | 
| 
       13 
     | 
    
         
            -
             
     | 
| 
       14 
     | 
    
         
            -
             
     | 
| 
       15 
     | 
    
         
            -
             
     | 
| 
      
 13 
     | 
    
         
            +
                # A sliding window is a structure that stores the most @max_size recent timestamps
         
     | 
| 
      
 14 
     | 
    
         
            +
                # like this: if @max_size = 4, current time is 10, @window =[5,7,9,10].
         
     | 
| 
      
 15 
     | 
    
         
            +
                # Another push of (11) at 11 sec would make @window [7,9,10,11], shifting off 5.
         
     | 
| 
       16 
16 
     | 
    
         | 
| 
       17 
     | 
    
         
            -
             
     | 
| 
       18 
     | 
    
         
            -
             
     | 
| 
       19 
     | 
    
         
            -
             
     | 
| 
       20 
     | 
    
         
            -
             
     | 
| 
      
 17 
     | 
    
         
            +
                def reject!(&block)
         
     | 
| 
      
 18 
     | 
    
         
            +
                  @window.reject!(&block)
         
     | 
| 
      
 19 
     | 
    
         
            +
                  self
         
     | 
| 
      
 20 
     | 
    
         
            +
                end
         
     | 
| 
       21 
21 
     | 
    
         | 
| 
       22 
     | 
    
         
            -
             
     | 
| 
       23 
     | 
    
         
            -
             
     | 
| 
       24 
     | 
    
         
            -
                   
     | 
| 
      
 22 
     | 
    
         
            +
                def push(value)
         
     | 
| 
      
 23 
     | 
    
         
            +
                  resize_to(@max_size - 1) # make room
         
     | 
| 
      
 24 
     | 
    
         
            +
                  @window << value
         
     | 
| 
      
 25 
     | 
    
         
            +
                  self
         
     | 
| 
      
 26 
     | 
    
         
            +
                end
         
     | 
| 
      
 27 
     | 
    
         
            +
                alias_method :<<, :push
         
     | 
| 
       25 
28 
     | 
    
         | 
| 
       26 
     | 
    
         
            -
             
     | 
| 
       27 
     | 
    
         
            -
             
     | 
| 
       28 
     | 
    
         
            -
             
     | 
| 
       29 
     | 
    
         
            -
             
     | 
| 
       30 
     | 
    
         
            -
             
     | 
| 
       31 
     | 
    
         
            -
                  alias_method :<<, :push
         
     | 
| 
      
 29 
     | 
    
         
            +
                def clear
         
     | 
| 
      
 30 
     | 
    
         
            +
                  @window.clear
         
     | 
| 
      
 31 
     | 
    
         
            +
                  self
         
     | 
| 
      
 32 
     | 
    
         
            +
                end
         
     | 
| 
      
 33 
     | 
    
         
            +
                alias_method :destroy, :clear
         
     | 
| 
       32 
34 
     | 
    
         | 
| 
       33 
     | 
    
         
            -
             
     | 
| 
       34 
     | 
    
         
            -
             
     | 
| 
       35 
     | 
    
         
            -
             
     | 
| 
       36 
     | 
    
         
            -
                   
     | 
| 
       37 
     | 
    
         
            -
             
     | 
| 
      
 35 
     | 
    
         
            +
                private
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                def resize_to(size)
         
     | 
| 
      
 38 
     | 
    
         
            +
                  @window = @window.last(size) if @window.size >= size
         
     | 
| 
      
 39 
     | 
    
         
            +
                end
         
     | 
| 
      
 40 
     | 
    
         
            +
              end
         
     | 
| 
       38 
41 
     | 
    
         | 
| 
       39 
     | 
    
         
            -
             
     | 
| 
      
 42 
     | 
    
         
            +
              module Simple
         
     | 
| 
      
 43 
     | 
    
         
            +
                class SlidingWindow # :nodoc:
         
     | 
| 
      
 44 
     | 
    
         
            +
                  include SlidingWindowBehavior
         
     | 
| 
       40 
45 
     | 
    
         | 
| 
       41 
     | 
    
         
            -
                  def  
     | 
| 
       42 
     | 
    
         
            -
                    @ 
     | 
| 
      
 46 
     | 
    
         
            +
                  def initialize(max_size:)
         
     | 
| 
      
 47 
     | 
    
         
            +
                    @max_size = max_size
         
     | 
| 
      
 48 
     | 
    
         
            +
                    @window = []
         
     | 
| 
       43 
49 
     | 
    
         
             
                  end
         
     | 
| 
       44 
50 
     | 
    
         
             
                end
         
     | 
| 
       45 
51 
     | 
    
         
             
              end
         
     | 
| 
       46 
52 
     | 
    
         | 
| 
       47 
53 
     | 
    
         
             
              module ThreadSafe
         
     | 
| 
       48 
     | 
    
         
            -
                class SlidingWindow 
     | 
| 
       49 
     | 
    
         
            -
                   
     | 
| 
       50 
     | 
    
         
            -
                    super
         
     | 
| 
       51 
     | 
    
         
            -
                    @lock = Mutex.new
         
     | 
| 
       52 
     | 
    
         
            -
                  end
         
     | 
| 
       53 
     | 
    
         
            -
             
     | 
| 
       54 
     | 
    
         
            -
                  # #size, #last, and #clear are not wrapped in a mutex. For the first two,
         
     | 
| 
       55 
     | 
    
         
            -
                  # the worst-case is a thread-switch at a timing where they'd receive an
         
     | 
| 
       56 
     | 
    
         
            -
                  # out-of-date value--which could happen with a mutex as well.
         
     | 
| 
       57 
     | 
    
         
            -
                  #
         
     | 
| 
       58 
     | 
    
         
            -
                  # As for clear, it's an all or nothing operation. Doesn't matter if we
         
     | 
| 
       59 
     | 
    
         
            -
                  # have the lock or not.
         
     | 
| 
       60 
     | 
    
         
            -
             
     | 
| 
       61 
     | 
    
         
            -
                  def reject!(*)
         
     | 
| 
       62 
     | 
    
         
            -
                    @lock.synchronize { super }
         
     | 
| 
       63 
     | 
    
         
            -
                  end
         
     | 
| 
      
 54 
     | 
    
         
            +
                class SlidingWindow
         
     | 
| 
      
 55 
     | 
    
         
            +
                  include SlidingWindowBehavior
         
     | 
| 
       64 
56 
     | 
    
         | 
| 
       65 
     | 
    
         
            -
                  def  
     | 
| 
       66 
     | 
    
         
            -
                    @ 
     | 
| 
      
 57 
     | 
    
         
            +
                  def initialize(max_size:)
         
     | 
| 
      
 58 
     | 
    
         
            +
                    @max_size = max_size
         
     | 
| 
      
 59 
     | 
    
         
            +
                    @window = Concurrent::Array.new
         
     | 
| 
       67 
60 
     | 
    
         
             
                  end
         
     | 
| 
       68 
61 
     | 
    
         
             
                end
         
     | 
| 
       69 
62 
     | 
    
         
             
              end
         
     | 
    
        data/lib/semian/version.rb
    CHANGED
    
    
    
        data/lib/semian.rb
    CHANGED
    
    | 
         @@ -4,6 +4,7 @@ require "forwardable" 
     | 
|
| 
       4 
4 
     | 
    
         
             
            require "logger"
         
     | 
| 
       5 
5 
     | 
    
         
             
            require "weakref"
         
     | 
| 
       6 
6 
     | 
    
         
             
            require "thread"
         
     | 
| 
      
 7 
     | 
    
         
            +
            require "concurrent-ruby"
         
     | 
| 
       7 
8 
     | 
    
         | 
| 
       8 
9 
     | 
    
         
             
            require "semian/version"
         
     | 
| 
       9 
10 
     | 
    
         
             
            require "semian/instrumentable"
         
     | 
| 
         @@ -110,6 +111,20 @@ module Semian 
     | 
|
| 
       110 
111 
     | 
    
         
             
              self.default_permissions = 0660
         
     | 
| 
       111 
112 
     | 
    
         
             
              self.default_force_config_validation = false
         
     | 
| 
       112 
113 
     | 
    
         | 
| 
      
 114 
     | 
    
         
            +
              # We only allow disabling thread-safety for parts of the code that are on the hot path.
         
     | 
| 
      
 115 
     | 
    
         
            +
              # Since locking there could have a significant impact. Everything else is enforced thread safety
         
     | 
| 
      
 116 
     | 
    
         
            +
              def thread_safe?
         
     | 
| 
      
 117 
     | 
    
         
            +
                return @thread_safe if defined?(@thread_safe)
         
     | 
| 
      
 118 
     | 
    
         
            +
             
     | 
| 
      
 119 
     | 
    
         
            +
                @thread_safe = true
         
     | 
| 
      
 120 
     | 
    
         
            +
              end
         
     | 
| 
      
 121 
     | 
    
         
            +
             
     | 
| 
      
 122 
     | 
    
         
            +
              def thread_safe=(thread_safe)
         
     | 
| 
      
 123 
     | 
    
         
            +
                @thread_safe = thread_safe
         
     | 
| 
      
 124 
     | 
    
         
            +
              end
         
     | 
| 
      
 125 
     | 
    
         
            +
             
     | 
| 
      
 126 
     | 
    
         
            +
              @reset_mutex = Mutex.new
         
     | 
| 
      
 127 
     | 
    
         
            +
             
     | 
| 
       113 
128 
     | 
    
         
             
              def issue_disabled_semaphores_warning
         
     | 
| 
       114 
129 
     | 
    
         
             
                return if defined?(@warning_issued)
         
     | 
| 
       115 
130 
     | 
    
         | 
| 
         @@ -200,7 +215,7 @@ module Semian 
     | 
|
| 
       200 
215 
     | 
    
         
             
                # of who the consumer was so that we can clear the resource reference if needed.
         
     | 
| 
       201 
216 
     | 
    
         
             
                consumer = args.delete(:consumer)
         
     | 
| 
       202 
217 
     | 
    
         
             
                if consumer&.class&.include?(Semian::Adapter) && !args[:dynamic]
         
     | 
| 
       203 
     | 
    
         
            -
                  consumer_set = ( 
     | 
| 
      
 218 
     | 
    
         
            +
                  consumer_set = consumers.compute_if_absent(name) { ObjectSpace::WeakMap.new }
         
     | 
| 
       204 
219 
     | 
    
         
             
                  consumer_set[consumer] = true
         
     | 
| 
       205 
220 
     | 
    
         
             
                end
         
     | 
| 
       206 
221 
     | 
    
         
             
                self[name] || register(name, **args)
         
     | 
| 
         @@ -233,7 +248,7 @@ module Semian 
     | 
|
| 
       233 
248 
     | 
    
         
             
                resource = resources.delete(name)
         
     | 
| 
       234 
249 
     | 
    
         
             
                if resource
         
     | 
| 
       235 
250 
     | 
    
         
             
                  resource.bulkhead&.unregister_worker
         
     | 
| 
       236 
     | 
    
         
            -
                  consumers_for_resource = consumers.delete(name) ||  
     | 
| 
      
 251 
     | 
    
         
            +
                  consumers_for_resource = consumers.delete(name) || ObjectSpace::WeakMap.new
         
     | 
| 
       237 
252 
     | 
    
         
             
                  consumers_for_resource.each_key(&:clear_semian_resource)
         
     | 
| 
       238 
253 
     | 
    
         
             
                end
         
     | 
| 
       239 
254 
     | 
    
         
             
              end
         
     | 
| 
         @@ -245,29 +260,11 @@ module Semian 
     | 
|
| 
       245 
260 
     | 
    
         
             
                end
         
     | 
| 
       246 
261 
     | 
    
         
             
              end
         
     | 
| 
       247 
262 
     | 
    
         | 
| 
       248 
     | 
    
         
            -
              # Retrieves a hash of all registered resources.
         
     | 
| 
       249 
     | 
    
         
            -
              def resources
         
     | 
| 
       250 
     | 
    
         
            -
                @resources ||= LRUHash.new
         
     | 
| 
       251 
     | 
    
         
            -
              end
         
     | 
| 
       252 
     | 
    
         
            -
             
     | 
| 
       253 
     | 
    
         
            -
              # Retrieves a hash of all registered resource consumers.
         
     | 
| 
       254 
     | 
    
         
            -
              def consumers
         
     | 
| 
       255 
     | 
    
         
            -
                @consumers ||= {}
         
     | 
| 
       256 
     | 
    
         
            -
              end
         
     | 
| 
       257 
     | 
    
         
            -
             
     | 
| 
       258 
263 
     | 
    
         
             
              def reset!
         
     | 
| 
       259 
     | 
    
         
            -
                @ 
     | 
| 
       260 
     | 
    
         
            -
             
     | 
| 
       261 
     | 
    
         
            -
             
     | 
| 
       262 
     | 
    
         
            -
             
     | 
| 
       263 
     | 
    
         
            -
              def thread_safe?
         
     | 
| 
       264 
     | 
    
         
            -
                return @thread_safe if defined?(@thread_safe)
         
     | 
| 
       265 
     | 
    
         
            -
             
     | 
| 
       266 
     | 
    
         
            -
                @thread_safe = true
         
     | 
| 
       267 
     | 
    
         
            -
              end
         
     | 
| 
       268 
     | 
    
         
            -
             
     | 
| 
       269 
     | 
    
         
            -
              def thread_safe=(thread_safe)
         
     | 
| 
       270 
     | 
    
         
            -
                @thread_safe = thread_safe
         
     | 
| 
      
 264 
     | 
    
         
            +
                @reset_mutex.synchronize do
         
     | 
| 
      
 265 
     | 
    
         
            +
                  @consumers = Concurrent::Map.new
         
     | 
| 
      
 266 
     | 
    
         
            +
                  @resources = LRUHash.new
         
     | 
| 
      
 267 
     | 
    
         
            +
                end
         
     | 
| 
       271 
268 
     | 
    
         
             
              end
         
     | 
| 
       272 
269 
     | 
    
         | 
| 
       273 
270 
     | 
    
         
             
              THREAD_BULKHEAD_DISABLED_VAR = :semian_bulkheads_disabled
         
     | 
| 
         @@ -285,6 +282,22 @@ module Semian 
     | 
|
| 
       285 
282 
     | 
    
         
             
                thread.thread_variable_set(THREAD_BULKHEAD_DISABLED_VAR, old_value)
         
     | 
| 
       286 
283 
     | 
    
         
             
              end
         
     | 
| 
       287 
284 
     | 
    
         | 
| 
      
 285 
     | 
    
         
            +
              def resources
         
     | 
| 
      
 286 
     | 
    
         
            +
                return @resources if defined?(@resources) && @resources
         
     | 
| 
      
 287 
     | 
    
         
            +
             
     | 
| 
      
 288 
     | 
    
         
            +
                @reset_mutex.synchronize do
         
     | 
| 
      
 289 
     | 
    
         
            +
                  @resources ||= LRUHash.new
         
     | 
| 
      
 290 
     | 
    
         
            +
                end
         
     | 
| 
      
 291 
     | 
    
         
            +
              end
         
     | 
| 
      
 292 
     | 
    
         
            +
             
     | 
| 
      
 293 
     | 
    
         
            +
              def consumers
         
     | 
| 
      
 294 
     | 
    
         
            +
                return @consumers if defined?(@consumers) && @consumers
         
     | 
| 
      
 295 
     | 
    
         
            +
             
     | 
| 
      
 296 
     | 
    
         
            +
                @reset_mutex.synchronize do
         
     | 
| 
      
 297 
     | 
    
         
            +
                  @consumers ||= Concurrent::Map.new
         
     | 
| 
      
 298 
     | 
    
         
            +
                end
         
     | 
| 
      
 299 
     | 
    
         
            +
              end
         
     | 
| 
      
 300 
     | 
    
         
            +
             
     | 
| 
       288 
301 
     | 
    
         
             
              private
         
     | 
| 
       289 
302 
     | 
    
         | 
| 
       290 
303 
     | 
    
         
             
              def create_circuit_breaker(name, **options)
         
     |