semian 0.12.0 → 0.13.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +235 -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 +12 -6
- data/lib/semian/redis.rb +15 -13
- 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.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.0
|
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-06-27 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
|