semian 0.12.0 → 0.13.2
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/CHANGELOG.md +243 -0
- data/LICENSE.md +21 -0
- data/README.md +836 -0
- data/ext/semian/extconf.rb +21 -19
- data/lib/semian/adapter.rb +8 -4
- data/lib/semian/circuit_breaker.rb +16 -10
- data/lib/semian/grpc.rb +32 -10
- data/lib/semian/instrumentable.rb +2 -0
- data/lib/semian/lru_hash.rb +15 -14
- data/lib/semian/mysql2.rb +13 -9
- data/lib/semian/net_http.rb +10 -4
- data/lib/semian/platform.rb +3 -1
- data/lib/semian/protected_resource.rb +5 -3
- data/lib/semian/rails.rb +33 -6
- data/lib/semian/redis.rb +16 -14
- data/lib/semian/redis_client.rb +5 -3
- data/lib/semian/resource.rb +5 -3
- data/lib/semian/simple_integer.rb +4 -2
- data/lib/semian/simple_sliding_window.rb +5 -3
- data/lib/semian/simple_state.rb +3 -1
- data/lib/semian/unprotected_resource.rb +2 -0
- data/lib/semian/version.rb +3 -1
- data/lib/semian.rb +61 -45
- metadata +11 -201
data/lib/semian/version.rb
CHANGED
data/lib/semian.rb
CHANGED
@@ -1,19 +1,21 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
5
|
-
|
6
|
-
require
|
7
|
-
|
8
|
-
require
|
9
|
-
require
|
10
|
-
require
|
11
|
-
require
|
12
|
-
require
|
13
|
-
require
|
14
|
-
require
|
15
|
-
require
|
16
|
-
require
|
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(
|
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
|
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,
|
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
|
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(
|
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,
|
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
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
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,8 @@ module Semian
|
|
185
197
|
end
|
186
198
|
|
187
199
|
def destroy(name)
|
188
|
-
|
189
|
-
|
190
|
-
end
|
200
|
+
resource = resources.delete(name)
|
201
|
+
resource&.destroy
|
191
202
|
end
|
192
203
|
|
193
204
|
def destroy_all_resources
|
@@ -204,17 +215,16 @@ module Semian
|
|
204
215
|
# Also clears any semian_resources
|
205
216
|
# in use by any semian adapters if the weak reference is still alive.
|
206
217
|
def unregister(name)
|
207
|
-
|
208
|
-
|
218
|
+
resource = resources.delete(name)
|
219
|
+
if resource
|
220
|
+
resource.bulkhead&.unregister_worker
|
209
221
|
consumers_for_resource = consumers.delete(name) || []
|
210
222
|
consumers_for_resource.each do |consumer|
|
211
|
-
|
212
|
-
|
213
|
-
consumer.clear_semian_resource
|
214
|
-
end
|
215
|
-
rescue WeakRef::RefError
|
216
|
-
next
|
223
|
+
if consumer.weakref_alive?
|
224
|
+
consumer.clear_semian_resource
|
217
225
|
end
|
226
|
+
rescue WeakRef::RefError
|
227
|
+
next
|
218
228
|
end
|
219
229
|
end
|
220
230
|
end
|
@@ -243,6 +253,7 @@ module Semian
|
|
243
253
|
|
244
254
|
def thread_safe?
|
245
255
|
return @thread_safe if defined?(@thread_safe)
|
256
|
+
|
246
257
|
@thread_safe = true
|
247
258
|
end
|
248
259
|
|
@@ -255,6 +266,7 @@ module Semian
|
|
255
266
|
def create_circuit_breaker(name, **options)
|
256
267
|
circuit_breaker = options.fetch(:circuit_breaker, true)
|
257
268
|
return unless circuit_breaker
|
269
|
+
|
258
270
|
require_keys!([:success_threshold, :error_threshold, :error_timeout], options)
|
259
271
|
|
260
272
|
exceptions = options[:exceptions] || []
|
@@ -277,8 +289,8 @@ module Semian
|
|
277
289
|
unless options[:thread_safety_disabled].nil?
|
278
290
|
logger.info(
|
279
291
|
"NOTE: thread_safety_disabled will be replaced by a global setting" \
|
280
|
-
|
281
|
-
|
292
|
+
"Semian is thread safe by default. It is possible" \
|
293
|
+
"to modify the value by using Semian.thread_safe=",
|
282
294
|
)
|
283
295
|
end
|
284
296
|
|
@@ -292,7 +304,11 @@ module Semian
|
|
292
304
|
|
293
305
|
permissions = options[:permissions] || default_permissions
|
294
306
|
timeout = options[:timeout] || 0
|
295
|
-
Resource.new(name,
|
307
|
+
::Semian::Resource.new(name,
|
308
|
+
tickets: options[:tickets],
|
309
|
+
quota: options[:quota],
|
310
|
+
permissions: permissions,
|
311
|
+
timeout: timeout)
|
296
312
|
end
|
297
313
|
|
298
314
|
def require_keys!(required, options)
|
@@ -304,13 +320,13 @@ module Semian
|
|
304
320
|
end
|
305
321
|
|
306
322
|
if Semian.semaphores_enabled?
|
307
|
-
require
|
323
|
+
require "semian/semian"
|
308
324
|
else
|
309
325
|
Semian::MAX_TICKETS = 0
|
310
326
|
end
|
311
327
|
|
312
328
|
if defined? ActiveSupport
|
313
|
-
ActiveSupport.on_load
|
314
|
-
require
|
329
|
+
ActiveSupport.on_load(:active_record) do
|
330
|
+
require "semian/rails"
|
315
331
|
end
|
316
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.
|
4
|
+
version: 0.13.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Scott Francis
|
@@ -10,213 +10,20 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2022-
|
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: redis-client
|
115
|
-
requirement: !ruby/object:Gem::Requirement
|
116
|
-
requirements:
|
117
|
-
- - ">="
|
118
|
-
- !ruby/object:Gem::Version
|
119
|
-
version: 0.2.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.2.0
|
127
|
-
- !ruby/object:Gem::Dependency
|
128
|
-
name: webrick
|
129
|
-
requirement: !ruby/object:Gem::Requirement
|
130
|
-
requirements:
|
131
|
-
- - ">="
|
132
|
-
- !ruby/object:Gem::Version
|
133
|
-
version: '0'
|
134
|
-
type: :development
|
135
|
-
prerelease: false
|
136
|
-
version_requirements: !ruby/object:Gem::Requirement
|
137
|
-
requirements:
|
138
|
-
- - ">="
|
139
|
-
- !ruby/object:Gem::Version
|
140
|
-
version: '0'
|
141
|
-
- !ruby/object:Gem::Dependency
|
142
|
-
name: toxiproxy
|
143
|
-
requirement: !ruby/object:Gem::Requirement
|
144
|
-
requirements:
|
145
|
-
- - "~>"
|
146
|
-
- !ruby/object:Gem::Version
|
147
|
-
version: 1.0.0
|
148
|
-
type: :development
|
149
|
-
prerelease: false
|
150
|
-
version_requirements: !ruby/object:Gem::Requirement
|
151
|
-
requirements:
|
152
|
-
- - "~>"
|
153
|
-
- !ruby/object:Gem::Version
|
154
|
-
version: 1.0.0
|
155
|
-
- !ruby/object:Gem::Dependency
|
156
|
-
name: grpc
|
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: mocha
|
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: memory_profiler
|
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'
|
197
|
-
- !ruby/object:Gem::Dependency
|
198
|
-
name: benchmark-memory
|
199
|
-
requirement: !ruby/object:Gem::Requirement
|
200
|
-
requirements:
|
201
|
-
- - ">="
|
202
|
-
- !ruby/object:Gem::Version
|
203
|
-
version: '0'
|
204
|
-
type: :development
|
205
|
-
prerelease: false
|
206
|
-
version_requirements: !ruby/object:Gem::Requirement
|
207
|
-
requirements:
|
208
|
-
- - ">="
|
209
|
-
- !ruby/object:Gem::Version
|
210
|
-
version: '0'
|
13
|
+
date: 2022-08-19 00:00:00.000000000 Z
|
14
|
+
dependencies: []
|
211
15
|
description: |2
|
212
16
|
A Ruby C extention that is used to control access to shared resources
|
213
17
|
across process boundaries with SysV semaphores.
|
214
|
-
email:
|
18
|
+
email: opensource@shopify.com
|
215
19
|
executables: []
|
216
20
|
extensions:
|
217
21
|
- ext/semian/extconf.rb
|
218
22
|
extra_rdoc_files: []
|
219
23
|
files:
|
24
|
+
- CHANGELOG.md
|
25
|
+
- LICENSE.md
|
26
|
+
- README.md
|
220
27
|
- ext/semian/extconf.rb
|
221
28
|
- ext/semian/resource.c
|
222
29
|
- ext/semian/resource.h
|
@@ -251,6 +58,9 @@ licenses:
|
|
251
58
|
- MIT
|
252
59
|
metadata:
|
253
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
|
254
64
|
post_install_message:
|
255
65
|
rdoc_options: []
|
256
66
|
require_paths:
|
@@ -266,7 +76,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
266
76
|
- !ruby/object:Gem::Version
|
267
77
|
version: '0'
|
268
78
|
requirements: []
|
269
|
-
rubygems_version: 3.
|
79
|
+
rubygems_version: 3.3.3
|
270
80
|
signing_key:
|
271
81
|
specification_version: 4
|
272
82
|
summary: Bulkheading for Ruby with SysV semaphores
|