semian 0.11.8 → 0.13.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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.11.8'
4
+ VERSION = "0.13.0"
3
5
  end
data/lib/semian.rb CHANGED
@@ -1,19 +1,21 @@
1
- require 'forwardable'
2
- require 'logger'
3
- require 'weakref'
4
- require 'thread'
5
-
6
- require 'semian/version'
7
- require 'semian/instrumentable'
8
- require 'semian/platform'
9
- require 'semian/resource'
10
- require 'semian/circuit_breaker'
11
- require 'semian/protected_resource'
12
- require 'semian/unprotected_resource'
13
- require 'semian/simple_sliding_window'
14
- require 'semian/simple_integer'
15
- require 'semian/simple_state'
16
- require 'semian/lru_hash'
1
+ # frozen_string_literal: true
2
+
3
+ require "forwardable"
4
+ require "logger"
5
+ require "weakref"
6
+ require "thread"
7
+
8
+ require "semian/version"
9
+ require "semian/instrumentable"
10
+ require "semian/platform"
11
+ require "semian/resource"
12
+ require "semian/circuit_breaker"
13
+ require "semian/protected_resource"
14
+ require "semian/unprotected_resource"
15
+ require "semian/simple_sliding_window"
16
+ require "semian/simple_integer"
17
+ require "semian/simple_state"
18
+ require "semian/lru_hash"
17
19
 
18
20
  #
19
21
  # === Overview
@@ -56,9 +58,17 @@ require 'semian/lru_hash'
56
58
  #
57
59
  # ===== Registering a resource
58
60
  #
59
- # Semian.register(:mysql_shard0, tickets: 10, timeout: 0.5, error_threshold: 3, error_timeout: 10, success_threshold: 2)
61
+ # Semian.register(
62
+ # :mysql_shard0,
63
+ # tickets: 10,
64
+ # timeout: 0.5,
65
+ # error_threshold: 3,
66
+ # error_timeout: 10,
67
+ # success_threshold: 2,
68
+ # )
60
69
  #
61
- # This registers a new resource called <code>:mysql_shard0</code> that has 10 tickets and a default timeout of 500 milliseconds.
70
+ # This registers a new resource called <code>:mysql_shard0</code> that has 10 tickets and
71
+ # a default timeout of 500 milliseconds.
62
72
  #
63
73
  # After 3 failures in the span of 10 seconds the circuit will be open.
64
74
  # After an additional 10 seconds it will transition to half-open.
@@ -70,8 +80,8 @@ require 'semian/lru_hash'
70
80
  # # Perform a MySQL query here
71
81
  # end
72
82
  #
73
- # This acquires a ticket for the <code>:mysql_shard0</code> resource. If we use the example above, the ticket count would
74
- # be lowered to 9 when block is executed, then raised to 10 when the block completes.
83
+ # This acquires a ticket for the <code>:mysql_shard0</code> resource. If we use the example above,
84
+ # the ticket count would be lowered to 9 when block is executed, then raised to 10 when the block completes.
75
85
  #
76
86
  # ===== Overriding the default timeout
77
87
  #
@@ -79,7 +89,8 @@ require 'semian/lru_hash'
79
89
  # # Perform a MySQL query here
80
90
  # end
81
91
  #
82
- # This is the same as the previous example, but overrides the timeout from the default value of 500 milliseconds to 1 second.
92
+ # This is the same as the previous example, but overrides the timeout
93
+ # from the default value of 500 milliseconds to 1 second.
83
94
  module Semian
84
95
  extend self
85
96
  extend Instrumentable
@@ -91,12 +102,14 @@ module Semian
91
102
  OpenCircuitError = Class.new(BaseError)
92
103
 
93
104
  attr_accessor :maximum_lru_size, :minimum_lru_time, :default_permissions, :namespace
105
+
94
106
  self.maximum_lru_size = 500
95
107
  self.minimum_lru_time = 300
96
108
  self.default_permissions = 0660
97
109
 
98
110
  def issue_disabled_semaphores_warning
99
111
  return if defined?(@warning_issued)
112
+
100
113
  @warning_issued = true
101
114
  if !sysv_semaphores_supported?
102
115
  logger.info("Semian sysv semaphores are not supported on #{RUBY_PLATFORM} - all operations will no-op")
@@ -119,7 +132,7 @@ module Semian
119
132
 
120
133
  attr_accessor :logger
121
134
 
122
- self.logger = Logger.new(STDERR)
135
+ self.logger = Logger.new($stderr)
123
136
 
124
137
  # Registers a resource.
125
138
  #
@@ -161,7 +174,7 @@ module Semian
161
174
  bulkhead = create_bulkhead(name, **options)
162
175
 
163
176
  if circuit_breaker.nil? && bulkhead.nil?
164
- raise ArgumentError, 'Both bulkhead and circuitbreaker cannot be disabled.'
177
+ raise ArgumentError, "Both bulkhead and circuitbreaker cannot be disabled."
165
178
  end
166
179
 
167
180
  resources[name] = ProtectedResource.new(name, bulkhead, circuit_breaker)
@@ -170,11 +183,10 @@ module Semian
170
183
  def retrieve_or_register(name, **args)
171
184
  # If consumer who retrieved / registered by a Semian::Adapter, keep track
172
185
  # of who the consumer was so that we can clear the resource reference if needed.
173
- if consumer = args.delete(:consumer)
174
- if consumer.class.include?(Semian::Adapter)
175
- consumers[name] ||= []
176
- consumers[name] << WeakRef.new(consumer)
177
- end
186
+ consumer = args.delete(:consumer)
187
+ if consumer&.class&.include?(Semian::Adapter)
188
+ consumers[name] ||= []
189
+ consumers[name] << WeakRef.new(consumer)
178
190
  end
179
191
  self[name] || register(name, **args)
180
192
  end
@@ -185,9 +197,13 @@ module Semian
185
197
  end
186
198
 
187
199
  def destroy(name)
188
- if resource = resources.delete(name)
189
- resource.destroy
190
- end
200
+ resource = resources.delete(name)
201
+ resource&.destroy
202
+ end
203
+
204
+ def destroy_all_resources
205
+ resources.values.each(&:destroy)
206
+ resources.clear
191
207
  end
192
208
 
193
209
  # Unregister will not destroy the semian resource, but it will
@@ -199,17 +215,16 @@ module Semian
199
215
  # Also clears any semian_resources
200
216
  # in use by any semian adapters if the weak reference is still alive.
201
217
  def unregister(name)
202
- if resource = resources.delete(name)
203
- resource.bulkhead.unregister_worker if resource.bulkhead
218
+ resource = resources.delete(name)
219
+ if resource
220
+ resource.bulkhead&.unregister_worker
204
221
  consumers_for_resource = consumers.delete(name) || []
205
222
  consumers_for_resource.each do |consumer|
206
- begin
207
- if consumer.weakref_alive?
208
- consumer.clear_semian_resource
209
- end
210
- rescue WeakRef::RefError
211
- next
223
+ if consumer.weakref_alive?
224
+ consumer.clear_semian_resource
212
225
  end
226
+ rescue WeakRef::RefError
227
+ next
213
228
  end
214
229
  end
215
230
  end
@@ -238,6 +253,7 @@ module Semian
238
253
 
239
254
  def thread_safe?
240
255
  return @thread_safe if defined?(@thread_safe)
256
+
241
257
  @thread_safe = true
242
258
  end
243
259
 
@@ -250,6 +266,7 @@ module Semian
250
266
  def create_circuit_breaker(name, **options)
251
267
  circuit_breaker = options.fetch(:circuit_breaker, true)
252
268
  return unless circuit_breaker
269
+
253
270
  require_keys!([:success_threshold, :error_threshold, :error_timeout], options)
254
271
 
255
272
  exceptions = options[:exceptions] || []
@@ -272,8 +289,8 @@ module Semian
272
289
  unless options[:thread_safety_disabled].nil?
273
290
  logger.info(
274
291
  "NOTE: thread_safety_disabled will be replaced by a global setting" \
275
- "Semian is thread safe by default. It is possible" \
276
- "to modify the value by using Semian.thread_safe=",
292
+ "Semian is thread safe by default. It is possible" \
293
+ "to modify the value by using Semian.thread_safe=",
277
294
  )
278
295
  end
279
296
 
@@ -287,7 +304,11 @@ module Semian
287
304
 
288
305
  permissions = options[:permissions] || default_permissions
289
306
  timeout = options[:timeout] || 0
290
- Resource.new(name, tickets: options[:tickets], quota: options[:quota], permissions: permissions, timeout: timeout)
307
+ ::Semian::Resource.new(name,
308
+ tickets: options[:tickets],
309
+ quota: options[:quota],
310
+ permissions: permissions,
311
+ timeout: timeout)
291
312
  end
292
313
 
293
314
  def require_keys!(required, options)
@@ -299,13 +320,13 @@ module Semian
299
320
  end
300
321
 
301
322
  if Semian.semaphores_enabled?
302
- require 'semian/semian'
323
+ require "semian/semian"
303
324
  else
304
325
  Semian::MAX_TICKETS = 0
305
326
  end
306
327
 
307
328
  if defined? ActiveSupport
308
- ActiveSupport.on_load :active_record do
309
- require 'semian/rails'
329
+ ActiveSupport.on_load(:active_record) do
330
+ require "semian/rails"
310
331
  end
311
332
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: semian
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.8
4
+ version: 0.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Scott Francis
@@ -10,199 +10,20 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2022-01-12 00:00:00.000000000 Z
14
- dependencies:
15
- - !ruby/object:Gem::Dependency
16
- name: rake-compiler
17
- requirement: !ruby/object:Gem::Requirement
18
- requirements:
19
- - - ">="
20
- - !ruby/object:Gem::Version
21
- version: '0'
22
- type: :development
23
- prerelease: false
24
- version_requirements: !ruby/object:Gem::Requirement
25
- requirements:
26
- - - ">="
27
- - !ruby/object:Gem::Version
28
- version: '0'
29
- - !ruby/object:Gem::Dependency
30
- name: rake
31
- requirement: !ruby/object:Gem::Requirement
32
- requirements:
33
- - - ">="
34
- - !ruby/object:Gem::Version
35
- version: '0'
36
- type: :development
37
- prerelease: false
38
- version_requirements: !ruby/object:Gem::Requirement
39
- requirements:
40
- - - ">="
41
- - !ruby/object:Gem::Version
42
- version: '0'
43
- - !ruby/object:Gem::Dependency
44
- name: timecop
45
- requirement: !ruby/object:Gem::Requirement
46
- requirements:
47
- - - ">="
48
- - !ruby/object:Gem::Version
49
- version: '0'
50
- type: :development
51
- prerelease: false
52
- version_requirements: !ruby/object:Gem::Requirement
53
- requirements:
54
- - - ">="
55
- - !ruby/object:Gem::Version
56
- version: '0'
57
- - !ruby/object:Gem::Dependency
58
- name: minitest
59
- requirement: !ruby/object:Gem::Requirement
60
- requirements:
61
- - - ">="
62
- - !ruby/object:Gem::Version
63
- version: '0'
64
- type: :development
65
- prerelease: false
66
- version_requirements: !ruby/object:Gem::Requirement
67
- requirements:
68
- - - ">="
69
- - !ruby/object:Gem::Version
70
- version: '0'
71
- - !ruby/object:Gem::Dependency
72
- name: pry-byebug
73
- requirement: !ruby/object:Gem::Requirement
74
- requirements:
75
- - - ">="
76
- - !ruby/object:Gem::Version
77
- version: '0'
78
- type: :development
79
- prerelease: false
80
- version_requirements: !ruby/object:Gem::Requirement
81
- requirements:
82
- - - ">="
83
- - !ruby/object:Gem::Version
84
- version: '0'
85
- - !ruby/object:Gem::Dependency
86
- name: mysql2
87
- requirement: !ruby/object:Gem::Requirement
88
- requirements:
89
- - - ">="
90
- - !ruby/object:Gem::Version
91
- version: '0'
92
- type: :development
93
- prerelease: false
94
- version_requirements: !ruby/object:Gem::Requirement
95
- requirements:
96
- - - ">="
97
- - !ruby/object:Gem::Version
98
- version: '0'
99
- - !ruby/object:Gem::Dependency
100
- name: redis
101
- requirement: !ruby/object:Gem::Requirement
102
- requirements:
103
- - - ">="
104
- - !ruby/object:Gem::Version
105
- version: '0'
106
- type: :development
107
- prerelease: false
108
- version_requirements: !ruby/object:Gem::Requirement
109
- requirements:
110
- - - ">="
111
- - !ruby/object:Gem::Version
112
- version: '0'
113
- - !ruby/object:Gem::Dependency
114
- name: webrick
115
- requirement: !ruby/object:Gem::Requirement
116
- requirements:
117
- - - ">="
118
- - !ruby/object:Gem::Version
119
- version: '0'
120
- type: :development
121
- prerelease: false
122
- version_requirements: !ruby/object:Gem::Requirement
123
- requirements:
124
- - - ">="
125
- - !ruby/object:Gem::Version
126
- version: '0'
127
- - !ruby/object:Gem::Dependency
128
- name: toxiproxy
129
- requirement: !ruby/object:Gem::Requirement
130
- requirements:
131
- - - "~>"
132
- - !ruby/object:Gem::Version
133
- version: 1.0.0
134
- type: :development
135
- prerelease: false
136
- version_requirements: !ruby/object:Gem::Requirement
137
- requirements:
138
- - - "~>"
139
- - !ruby/object:Gem::Version
140
- version: 1.0.0
141
- - !ruby/object:Gem::Dependency
142
- name: grpc
143
- requirement: !ruby/object:Gem::Requirement
144
- requirements:
145
- - - ">="
146
- - !ruby/object:Gem::Version
147
- version: '0'
148
- type: :development
149
- prerelease: false
150
- version_requirements: !ruby/object:Gem::Requirement
151
- requirements:
152
- - - ">="
153
- - !ruby/object:Gem::Version
154
- version: '0'
155
- - !ruby/object:Gem::Dependency
156
- name: mocha
157
- requirement: !ruby/object:Gem::Requirement
158
- requirements:
159
- - - ">="
160
- - !ruby/object:Gem::Version
161
- version: '0'
162
- type: :development
163
- prerelease: false
164
- version_requirements: !ruby/object:Gem::Requirement
165
- requirements:
166
- - - ">="
167
- - !ruby/object:Gem::Version
168
- version: '0'
169
- - !ruby/object:Gem::Dependency
170
- name: memory_profiler
171
- requirement: !ruby/object:Gem::Requirement
172
- requirements:
173
- - - ">="
174
- - !ruby/object:Gem::Version
175
- version: '0'
176
- type: :development
177
- prerelease: false
178
- version_requirements: !ruby/object:Gem::Requirement
179
- requirements:
180
- - - ">="
181
- - !ruby/object:Gem::Version
182
- version: '0'
183
- - !ruby/object:Gem::Dependency
184
- name: benchmark-memory
185
- requirement: !ruby/object:Gem::Requirement
186
- requirements:
187
- - - ">="
188
- - !ruby/object:Gem::Version
189
- version: '0'
190
- type: :development
191
- prerelease: false
192
- version_requirements: !ruby/object:Gem::Requirement
193
- requirements:
194
- - - ">="
195
- - !ruby/object:Gem::Version
196
- version: '0'
13
+ date: 2022-06-27 00:00:00.000000000 Z
14
+ dependencies: []
197
15
  description: |2
198
16
  A Ruby C extention that is used to control access to shared resources
199
17
  across process boundaries with SysV semaphores.
200
- email: scott.francis@shopify.com
18
+ email: opensource@shopify.com
201
19
  executables: []
202
20
  extensions:
203
21
  - ext/semian/extconf.rb
204
22
  extra_rdoc_files: []
205
23
  files:
24
+ - CHANGELOG.md
25
+ - LICENSE.md
26
+ - README.md
206
27
  - ext/semian/extconf.rb
207
28
  - ext/semian/resource.c
208
29
  - ext/semian/resource.h
@@ -225,6 +46,7 @@ files:
225
46
  - lib/semian/protected_resource.rb
226
47
  - lib/semian/rails.rb
227
48
  - lib/semian/redis.rb
49
+ - lib/semian/redis_client.rb
228
50
  - lib/semian/resource.rb
229
51
  - lib/semian/simple_integer.rb
230
52
  - lib/semian/simple_sliding_window.rb
@@ -236,6 +58,9 @@ licenses:
236
58
  - MIT
237
59
  metadata:
238
60
  allowed_push_host: https://rubygems.org
61
+ bug_tracker_uri: https://github.com/Shopify/semian/issues
62
+ changelog_uri: https://github.com/Shopify/semian/blob/master/CHANGELOG.md
63
+ source_code_uri: https://github.com/Shopify/semian
239
64
  post_install_message:
240
65
  rdoc_options: []
241
66
  require_paths:
@@ -251,7 +76,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
251
76
  - !ruby/object:Gem::Version
252
77
  version: '0'
253
78
  requirements: []
254
- rubygems_version: 3.2.20
79
+ rubygems_version: 3.3.3
255
80
  signing_key:
256
81
  specification_version: 4
257
82
  summary: Bulkheading for Ruby with SysV semaphores