semian 0.12.0 → 0.13.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,33 +1,35 @@
1
- $LOAD_PATH.unshift File.expand_path("../../../lib", __FILE__)
1
+ # frozen_string_literal: true
2
2
 
3
- require 'semian/platform'
3
+ $LOAD_PATH.unshift(File.expand_path("../../../lib", __FILE__))
4
+
5
+ require "semian/platform"
4
6
 
5
7
  unless Semian.sysv_semaphores_supported?
6
- File.write "Makefile", <<MAKEFILE
7
- all:
8
- clean:
9
- install:
10
- MAKEFILE
8
+ File.write("Makefile", <<~MAKEFILE)
9
+ all:
10
+ clean:
11
+ install:
12
+ MAKEFILE
11
13
  exit
12
14
  end
13
15
 
14
- require 'mkmf'
16
+ require "mkmf"
15
17
 
16
- abort 'openssl is missing. please install openssl.' unless find_header('openssl/sha.h')
17
- abort 'openssl is missing. please install openssl.' unless find_library('crypto', 'SHA1')
18
+ abort "openssl is missing. please install openssl." unless find_header("openssl/sha.h")
19
+ abort "openssl is missing. please install openssl." unless find_library("crypto", "SHA1")
18
20
 
19
- have_header 'sys/ipc.h'
20
- have_header 'sys/sem.h'
21
- have_header 'sys/types.h'
21
+ have_header "sys/ipc.h"
22
+ have_header "sys/sem.h"
23
+ have_header "sys/types.h"
22
24
 
23
- have_func 'rb_thread_blocking_region'
24
- have_func 'rb_thread_call_without_gvl'
25
+ have_func "rb_thread_blocking_region"
26
+ have_func "rb_thread_call_without_gvl"
25
27
 
26
28
  $CFLAGS = "-D_GNU_SOURCE -Werror -Wall "
27
- if ENV.key?('DEBUG')
28
- $CFLAGS << "-O0 -g -DDEBUG"
29
+ $CFLAGS += if ENV.key?("DEBUG")
30
+ "-O0 -g -DDEBUG"
29
31
  else
30
- $CFLAGS << "-O3"
32
+ "-O3"
31
33
  end
32
34
 
33
- create_makefile('semian/semian')
35
+ create_makefile("semian/semian")
@@ -1,9 +1,11 @@
1
- require 'semian'
1
+ # frozen_string_literal: true
2
+
3
+ require "semian"
2
4
 
3
5
  module Semian
4
6
  module Adapter
5
7
  def semian_identifier
6
- raise NotImplementedError.new("Semian adapters must implement a `semian_identifier` method")
8
+ raise NotImplementedError, "Semian adapters must implement a `semian_identifier` method"
7
9
  end
8
10
 
9
11
  def semian_resource
@@ -31,6 +33,7 @@ module Semian
31
33
 
32
34
  def acquire_semian_resource(scope:, adapter:, &block)
33
35
  return yield if resource_already_acquired?
36
+
34
37
  semian_resource.acquire(scope: scope, adapter: adapter, resource: self) do
35
38
  mark_resource_as_acquired(&block)
36
39
  end
@@ -48,16 +51,17 @@ module Semian
48
51
 
49
52
  def semian_options
50
53
  return @semian_options if defined? @semian_options
54
+
51
55
  options = raw_semian_options
52
56
  @semian_options = options && options.map { |k, v| [k.to_sym, v] }.to_h
53
57
  end
54
58
 
55
59
  def raw_semian_options
56
- raise NotImplementedError.new("Semian adapters must implement a `raw_semian_options` method")
60
+ raise NotImplementedError, "Semian adapters must implement a `raw_semian_options` method"
57
61
  end
58
62
 
59
63
  def resource_exceptions
60
- raise NotImplementedError.new("Semian adapters must implement a `resource_exceptions` method")
64
+ raise NotImplementedError, "Semian adapters must implement a `resource_exceptions` method"
61
65
  end
62
66
 
63
67
  def resource_already_acquired?
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Semian
2
- class CircuitBreaker #:nodoc:
4
+ class CircuitBreaker # :nodoc:
3
5
  extend Forwardable
4
6
 
5
7
  def_delegators :@state, :closed?, :open?, :half_open?
@@ -7,7 +9,9 @@ module Semian
7
9
  attr_reader :name, :half_open_resource_timeout, :error_timeout, :state, :last_error
8
10
 
9
11
  def initialize(name, exceptions:, success_threshold:, error_threshold:,
10
- error_timeout:, implementation:, half_open_resource_timeout: nil, error_threshold_timeout: nil)
12
+ error_timeout:, implementation:, half_open_resource_timeout: nil,
13
+ error_threshold_timeout: nil)
14
+
11
15
  @name = name.to_sym
12
16
  @success_count_threshold = success_threshold
13
17
  @error_count_threshold = error_threshold
@@ -25,6 +29,7 @@ module Semian
25
29
 
26
30
  def acquire(resource = nil, &block)
27
31
  return yield if disabled?
32
+
28
33
  transition_to_half_open if transition_to_half_open?
29
34
 
30
35
  raise OpenCircuitError unless request_allowed?
@@ -63,6 +68,7 @@ module Semian
63
68
 
64
69
  def mark_success
65
70
  return unless half_open?
71
+
66
72
  @successes.increment
67
73
  transition_to_close if success_threshold_reached?
68
74
  end
@@ -80,8 +86,7 @@ module Semian
80
86
  end
81
87
 
82
88
  def in_use?
83
- return false if error_timeout_expired?
84
- @errors.size > 0
89
+ !error_timeout_expired? && !@errors.empty?
85
90
  end
86
91
 
87
92
  private
@@ -117,6 +122,7 @@ module Semian
117
122
  def error_timeout_expired?
118
123
  last_error_time = @errors.last
119
124
  return false unless last_error_time
125
+
120
126
  Time.at(last_error_time) + @error_timeout < Time.now
121
127
  end
122
128
 
@@ -133,12 +139,12 @@ module Semian
133
139
  return if @state.nil? || new_state == @state.value
134
140
 
135
141
  str = "[#{self.class.name}] State transition from #{@state.value} to #{new_state}."
136
- str << " success_count=#{@successes.value} error_count=#{@errors.size}"
137
- str << " success_count_threshold=#{@success_count_threshold} error_count_threshold=#{@error_count_threshold}"
138
- str << " error_timeout=#{@error_timeout} error_last_at=\"#{@errors.last}\""
139
- str << " name=\"#{@name}\""
142
+ str += " success_count=#{@successes.value} error_count=#{@errors.size}"
143
+ str += " success_count_threshold=#{@success_count_threshold} error_count_threshold=#{@error_count_threshold}"
144
+ str += " error_timeout=#{@error_timeout} error_last_at=\"#{@errors.last}\""
145
+ str += " name=\"#{@name}\""
140
146
  if new_state == :open && @last_error
141
- str << " last_error_message=#{@last_error.message.inspect}"
147
+ str += " last_error_message=#{@last_error.message.inspect}"
142
148
  end
143
149
 
144
150
  Semian.logger.info(str)
@@ -149,7 +155,7 @@ module Semian
149
155
  end
150
156
 
151
157
  def disabled?
152
- ENV['SEMIAN_CIRCUIT_BREAKER_DISABLED'] || ENV['SEMIAN_DISABLED']
158
+ ENV["SEMIAN_CIRCUIT_BREAKER_DISABLED"] || ENV["SEMIAN_DISABLED"]
153
159
  end
154
160
 
155
161
  def maybe_with_half_open_resource_timeout(resource, &block)
data/lib/semian/grpc.rb CHANGED
@@ -1,5 +1,7 @@
1
- require 'semian/adapter'
2
- require 'grpc'
1
+ # frozen_string_literal: true
2
+
3
+ require "semian/adapter"
4
+ require "grpc"
3
5
 
4
6
  module GRPC
5
7
  GRPC::Unavailable.include(::Semian::AdapterError)
@@ -22,7 +24,6 @@ end
22
24
 
23
25
  module Semian
24
26
  module GRPC
25
- attr_reader :raw_semian_options
26
27
  include Semian::Adapter
27
28
 
28
29
  ResourceBusyError = ::GRPC::ResourceBusyError
@@ -40,6 +41,7 @@ module Semian
40
41
 
41
42
  def semian_configuration=(configuration)
42
43
  raise Semian::GRPC::SemianConfigurationChangedError unless @semian_configuration.nil?
44
+
43
45
  @semian_configuration = configuration
44
46
  end
45
47
 
@@ -52,10 +54,10 @@ module Semian
52
54
  @raw_semian_options ||= begin
53
55
  # If the host is empty, it's possible that the adapter was initialized
54
56
  # with the channel. Therefore, we look into the channel to find the host
55
- if @host.empty?
56
- host = @ch.target
57
+ host = if @host.empty?
58
+ @ch.target
57
59
  else
58
- host = @host
60
+ @host
59
61
  end
60
62
  @raw_semian_options = Semian::GRPC.retrieve_semian_configuration(host)
61
63
  @raw_semian_options = @raw_semian_options.dup unless @raw_semian_options.nil?
@@ -81,22 +83,42 @@ module Semian
81
83
 
82
84
  def request_response(*, **)
83
85
  return super if disabled?
84
- acquire_semian_resource(adapter: :grpc, scope: :request_response) { super }
86
+
87
+ acquire_semian_resource_grpc(scope: :request_response) { super }
85
88
  end
86
89
 
87
90
  def client_streamer(*, **)
88
91
  return super if disabled?
89
- acquire_semian_resource(adapter: :grpc, scope: :client_streamer) { super }
92
+
93
+ acquire_semian_resource_grpc(scope: :client_streamer) { super }
90
94
  end
91
95
 
92
96
  def server_streamer(*, **)
93
97
  return super if disabled?
94
- acquire_semian_resource(adapter: :grpc, scope: :server_streamer) { super }
98
+
99
+ acquire_semian_resource_grpc(scope: :server_streamer) { super }
95
100
  end
96
101
 
97
102
  def bidi_streamer(*, **)
98
103
  return super if disabled?
99
- acquire_semian_resource(adapter: :grpc, scope: :bidi_streamer) { super }
104
+
105
+ acquire_semian_resource_grpc(scope: :bidi_streamer) { super }
106
+ end
107
+
108
+ def acquire_semian_resource_grpc(scope:)
109
+ acquire_semian_resource(adapter: :grpc, scope: scope) do
110
+ result = yield
111
+ handle_operation(result, scope) if result.is_a?(::GRPC::ActiveCall::Operation)
112
+ result
113
+ end
114
+ end
115
+
116
+ def handle_operation(operation, scope)
117
+ execute = operation.singleton_method(:execute)
118
+ operation.instance_variable_set(:@semian, self)
119
+ operation.define_singleton_method(:execute) do
120
+ @semian.send(:acquire_semian_resource, **{ adapter: :grpc, scope: scope }) { execute.call }
121
+ end
100
122
  end
101
123
  end
102
124
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Semian
2
4
  module Instrumentable
3
5
  def subscribe(name = rand, &block)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class LRUHash
2
4
  # This LRU (Least Recently Used) hash will allow
3
5
  # the cleaning of resources as time goes on.
@@ -120,10 +122,10 @@ class LRUHash
120
122
 
121
123
  def clear_unused_resources
122
124
  payload = {
123
- size: @table.size,
124
- examined: 0,
125
- cleared: 0,
126
- elapsed: nil,
125
+ size: @table.size,
126
+ examined: 0,
127
+ cleared: 0,
128
+ elapsed: nil,
127
129
  }
128
130
  timer_start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
129
131
 
@@ -155,20 +157,19 @@ class LRUHash
155
157
  end
156
158
  end
157
159
 
158
- EXCEPTION_NEVER = {Exception => :never}.freeze
159
- EXCEPTION_IMMEDIATE = {Exception => :immediate}.freeze
160
+ EXCEPTION_NEVER = { Exception => :never }.freeze
161
+ EXCEPTION_IMMEDIATE = { Exception => :immediate }.freeze
160
162
  private_constant :EXCEPTION_NEVER
161
163
  private_constant :EXCEPTION_IMMEDIATE
162
164
 
163
- def try_synchronize
165
+ def try_synchronize(&block)
164
166
  Thread.handle_interrupt(EXCEPTION_NEVER) do
165
- begin
166
- return false unless @lock.try_lock
167
- Thread.handle_interrupt(EXCEPTION_IMMEDIATE) { yield }
168
- true
169
- ensure
170
- @lock.unlock if @lock.owned?
171
- end
167
+ return false unless @lock.try_lock
168
+
169
+ Thread.handle_interrupt(EXCEPTION_IMMEDIATE, &block)
170
+ true
171
+ ensure
172
+ @lock.unlock if @lock.owned?
172
173
  end
173
174
  end
174
175
  end
data/lib/semian/mysql2.rb CHANGED
@@ -1,5 +1,7 @@
1
- require 'semian/adapter'
2
- require 'mysql2'
1
+ # frozen_string_literal: true
2
+
3
+ require "semian/adapter"
4
+ require "mysql2"
3
5
 
4
6
  module Mysql2
5
7
  Mysql2::Error.include(::Semian::AdapterError)
@@ -32,13 +34,13 @@ module Semian
32
34
  CircuitOpenError = ::Mysql2::CircuitOpenError
33
35
  PingFailure = Class.new(::Mysql2::Error)
34
36
 
35
- DEFAULT_HOST = 'localhost'
37
+ DEFAULT_HOST = "localhost"
36
38
  DEFAULT_PORT = 3306
37
39
 
38
40
  QUERY_WHITELIST = Regexp.union(
39
- /\A(?:\/\*.*?\*\/)?\s*ROLLBACK/i,
40
- /\A(?:\/\*.*?\*\/)?\s*COMMIT/i,
41
- /\A(?:\/\*.*?\*\/)?\s*RELEASE\s+SAVEPOINT/i,
41
+ %r{\A(?:/\*.*?\*/)?\s*ROLLBACK}i,
42
+ %r{\A(?:/\*.*?\*/)?\s*COMMIT}i,
43
+ %r{\A(?:/\*.*?\*/)?\s*RELEASE\s+SAVEPOINT}i,
42
44
  )
43
45
 
44
46
  # The naked methods are exposed as `raw_query` and `raw_connect` for instrumentation purpose
@@ -55,7 +57,8 @@ module Semian
55
57
 
56
58
  def semian_identifier
57
59
  @semian_identifier ||= begin
58
- unless name = semian_options && semian_options[:name]
60
+ name = semian_options && semian_options[:name]
61
+ unless name
59
62
  host = query_options[:host] || DEFAULT_HOST
60
63
  port = query_options[:port] || DEFAULT_PORT
61
64
  name = "#{host}:#{port}"
@@ -68,7 +71,7 @@ module Semian
68
71
  result = nil
69
72
  acquire_semian_resource(adapter: :mysql, scope: :ping) do
70
73
  result = raw_ping
71
- raise PingFailure.new(result.to_s) unless result
74
+ raise PingFailure, result.to_s unless result
72
75
  end
73
76
  result
74
77
  rescue ResourceBusyError, CircuitOpenError, PingFailure
@@ -113,6 +116,7 @@ module Semian
113
116
  # data that is not recognized as a valid encoding, in which case we just
114
117
  # return false.
115
118
  return false unless sql.valid_encoding?
119
+
116
120
  raise
117
121
  end
118
122
 
@@ -132,7 +136,7 @@ module Semian
132
136
 
133
137
  def raw_semian_options
134
138
  return query_options[:semian] if query_options.key?(:semian)
135
- return query_options['semian'.freeze] if query_options.key?('semian'.freeze)
139
+ return query_options["semian"] if query_options.key?("semian")
136
140
  end
137
141
  end
138
142
  end
@@ -1,5 +1,7 @@
1
- require 'semian/adapter'
2
- require 'net/http'
1
+ # frozen_string_literal: true
2
+
3
+ require "semian/adapter"
4
+ require "net/http"
3
5
 
4
6
  module Net
5
7
  ProtocolError.include(::Semian::AdapterError)
@@ -40,10 +42,11 @@ module Semian
40
42
  ::Net::ProtocolError,
41
43
  ::EOFError,
42
44
  ::IOError,
43
- ::SystemCallError, # includes ::Errno::EINVAL, ::Errno::ECONNRESET, ::Errno::ECONNREFUSED, ::Errno::ETIMEDOUT, and more
45
+ ::SystemCallError, # includes ::Errno::EINVAL, ::Errno::ECONNRESET,
46
+ # ::Errno::ECONNREFUSED, ::Errno::ETIMEDOUT, and more
44
47
  ].freeze # Net::HTTP can throw many different errors, this tries to capture most of them
45
48
 
46
- module ClassMethods
49
+ module ClassMethods
47
50
  def new(*args, semian: true)
48
51
  http = super(*args)
49
52
  http.instance_variable_set(:@semian_enabled, semian)
@@ -57,6 +60,7 @@ module Semian
57
60
 
58
61
  def semian_configuration=(configuration)
59
62
  raise Semian::NetHTTP::SemianConfigurationChangedError unless @semian_configuration.nil?
63
+
60
64
  @semian_configuration = configuration
61
65
  end
62
66
 
@@ -88,11 +92,13 @@ module Semian
88
92
 
89
93
  def connect
90
94
  return super if disabled?
95
+
91
96
  acquire_semian_resource(adapter: :http, scope: :connection) { super }
92
97
  end
93
98
 
94
99
  def transport_request(*)
95
100
  return super if disabled?
101
+
96
102
  acquire_semian_resource(adapter: :http, scope: :query) do
97
103
  handle_error_responses(super)
98
104
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Semian
2
4
  extend self
3
5
 
@@ -11,6 +13,6 @@ module Semian
11
13
  end
12
14
 
13
15
  def disabled?
14
- ENV['SEMIAN_SEMAPHORES_DISABLED'] || ENV['SEMIAN_DISABLED']
16
+ ENV["SEMIAN_SEMAPHORES_DISABLED"] || ENV["SEMIAN_DISABLED"]
15
17
  end
16
18
  end
@@ -1,10 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Semian
2
4
  class ProtectedResource
3
5
  extend Forwardable
4
6
 
5
7
  def_delegators :@bulkhead, :destroy, :count, :semid, :tickets, :registered_workers
6
8
  def_delegators :@circuit_breaker, :reset, :mark_failed, :mark_success, :request_allowed?,
7
- :open?, :closed?, :half_open?
9
+ :open?, :closed?, :half_open?
8
10
 
9
11
  attr_reader :bulkhead, :circuit_breaker, :name
10
12
  attr_accessor :updated_at
@@ -17,8 +19,8 @@ module Semian
17
19
  end
18
20
 
19
21
  def destroy
20
- @bulkhead.destroy unless @bulkhead.nil?
21
- @circuit_breaker.destroy unless @circuit_breaker.nil?
22
+ @bulkhead&.destroy
23
+ @circuit_breaker&.destroy
22
24
  end
23
25
 
24
26
  def acquire(timeout: nil, scope: nil, adapter: nil, resource: nil)
data/lib/semian/rails.rb CHANGED
@@ -1,9 +1,15 @@
1
- require 'active_record/connection_adapters/abstract_adapter'
1
+ # frozen_string_literal: true
2
2
 
3
- class ActiveRecord::ConnectionAdapters::AbstractAdapter
4
- def semian_resource
5
- # support for https://github.com/rails/rails/commit/d86fd6415c0dfce6fadb77e74696cf728e5eb76b
6
- connection = instance_variable_defined?(:@raw_connection) ? @raw_connection : @connection
7
- connection.semian_resource
3
+ require "active_record/connection_adapters/abstract_adapter"
4
+
5
+ module ActiveRecord
6
+ module ConnectionAdapters
7
+ class AbstractAdapter
8
+ def semian_resource
9
+ # support for https://github.com/rails/rails/commit/d86fd6415c0dfce6fadb77e74696cf728e5eb76b
10
+ connection = instance_variable_defined?(:@raw_connection) ? @raw_connection : @connection
11
+ connection.semian_resource
12
+ end
13
+ end
8
14
  end
9
15
  end
data/lib/semian/redis.rb CHANGED
@@ -1,5 +1,7 @@
1
- require 'semian/adapter'
2
- require 'redis'
1
+ # frozen_string_literal: true
2
+
3
+ require "semian/adapter"
4
+ require "redis"
3
5
 
4
6
  class Redis
5
7
  Redis::BaseConnectionError.include(::Semian::AdapterError)
@@ -17,7 +19,7 @@ class Redis
17
19
  end
18
20
 
19
21
  class ConnectionError < Redis::BaseConnectionError
20
- # A Connection Reset is a fast failure and we don't want to track these errors in
22
+ # A Connection Reset is a fast failure and we don't want to track these errors in
21
23
  # semian
22
24
  def marks_semian_circuits?
23
25
  message != "Connection lost (ECONNRESET)"
@@ -90,12 +92,11 @@ module Semian
90
92
 
91
93
  def connect
92
94
  acquire_semian_resource(adapter: :redis, scope: :connection) do
93
- begin
94
- raw_connect
95
- rescue SocketError, RuntimeError => e
96
- raise ResolveError.new(semian_identifier) if dns_resolve_failure?(e.cause || e)
97
- raise
98
- end
95
+ raw_connect
96
+ rescue SocketError, RuntimeError => e
97
+ raise ResolveError, semian_identifier if dns_resolve_failure?(e.cause || e)
98
+
99
+ raise
99
100
  end
100
101
  end
101
102
 
@@ -107,7 +108,7 @@ module Semian
107
108
 
108
109
  begin
109
110
  connection.timeout = temp_timeout if connected?
110
- options[:timeout] = Float(temp_timeout),
111
+ options[:timeout] = Float(temp_timeout)
111
112
  options[:connect_timeout] = Float(temp_timeout)
112
113
  options[:read_timeout] = Float(temp_timeout)
113
114
  options[:write_timeout] = Float(temp_timeout)
@@ -133,17 +134,18 @@ module Semian
133
134
 
134
135
  def raw_semian_options
135
136
  return options[:semian] if options.key?(:semian)
136
- return options['semian'.freeze] if options.key?('semian'.freeze)
137
+ return options["semian"] if options.key?("semian")
137
138
  end
138
139
 
139
140
  def raise_if_out_of_memory(reply)
140
141
  return unless reply.is_a?(::Redis::CommandError)
141
142
  return unless reply.message.start_with?("OOM ")
142
- raise ::Redis::OutOfMemoryError.new(reply.message)
143
+
144
+ raise ::Redis::OutOfMemoryError, reply.message
143
145
  end
144
146
 
145
147
  def dns_resolve_failure?(e)
146
- e.to_s.match?(/(can't resolve)|(name or service not known)|(nodename nor servname provided, or not known)|(failure in name resolution)/i)
148
+ e.to_s.match?(/(can't resolve)|(name or service not known)|(nodename nor servname provided, or not known)|(failure in name resolution)/i) # rubocop:disable Layout/LineLength
147
149
  end
148
150
  end
149
151
  end
@@ -1,5 +1,7 @@
1
- require 'semian/adapter'
2
- require 'redis-client'
1
+ # frozen_string_literal: true
2
+
3
+ require "semian/adapter"
4
+ require "redis-client"
3
5
 
4
6
  class RedisClient
5
7
  ConnectionError.include(::Semian::AdapterError)
@@ -104,7 +106,7 @@ module Semian
104
106
  include RedisClientCommon
105
107
  define_method(:semian_resource, Semian::Adapter.instance_method(:semian_resource))
106
108
  define_method(:clear_semian_resource, Semian::Adapter.instance_method(:clear_semian_resource))
107
- end
109
+ end
108
110
  end
109
111
 
110
112
  RedisClient.prepend(Semian::RedisClient)
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Semian
2
- class Resource #:nodoc:
3
- attr_reader :tickets, :name
4
+ class Resource # :nodoc:
5
+ attr_reader :name
4
6
 
5
7
  class << Semian::Resource
6
8
  # Ensure that there can only be one resource of a given type
@@ -55,7 +57,7 @@ module Semian
55
57
  end
56
58
 
57
59
  def key
58
- '0x00000000'
60
+ "0x00000000"
59
61
  end
60
62
 
61
63
  def in_use?
@@ -1,8 +1,10 @@
1
- require 'thread'
1
+ # frozen_string_literal: true
2
+
3
+ require "thread"
2
4
 
3
5
  module Semian
4
6
  module Simple
5
- class Integer #:nodoc:
7
+ class Integer # :nodoc:
6
8
  attr_accessor :value
7
9
 
8
10
  def initialize
@@ -1,11 +1,13 @@
1
- require 'thread'
1
+ # frozen_string_literal: true
2
+
3
+ require "thread"
2
4
 
3
5
  module Semian
4
6
  module Simple
5
- class SlidingWindow #:nodoc:
7
+ class SlidingWindow # :nodoc:
6
8
  extend Forwardable
7
9
 
8
- def_delegators :@window, :size, :last
10
+ def_delegators :@window, :size, :last, :empty?
9
11
  attr_reader :max_size
10
12
 
11
13
  # A sliding window is a structure that stores the most @max_size recent timestamps
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Semian
2
4
  module Simple
3
- class State #:nodoc:
5
+ class State # :nodoc:
4
6
  def initialize
5
7
  reset
6
8
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Semian
2
4
  # This class acts as a replacement for `ProtectedResource` when
3
5
  # the semian configuration of an `Adapter` is missing or explicitly disabled
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Semian
2
- VERSION = '0.12.0'
4
+ VERSION = "0.13.0"
3
5
  end