semian 0.13.2 → 0.15.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 540294c5a9ecdfdcbafcdc1485afd1314a94fd869501bc6795ee327606d3e799
4
- data.tar.gz: 5855959232d25ea3c2da1f7ca7096c18afb15161ac8116e8f1ece9792fd456e4
3
+ metadata.gz: 9610bcda3bdfb95c885c6c31c4a2450a4c31824f877ad38e7ca3c34c4fd57d6c
4
+ data.tar.gz: d748c2da29ba2ca844bc74354591196a6645a915d725fea07ab743d0b6343bf2
5
5
  SHA512:
6
- metadata.gz: c7549cd0c6dc515733612fcd7b200c23467104c5616ff9501b65a554712e0449d07d8d2d479b45962cffb87c8e6cd2fc82d695a1d9f399a5724b3b4c241c59a8
7
- data.tar.gz: cf31ff975016b22e101db10813d73ab8288584657c9f7319ef222790dcd052d3ab45caedcca2639140d2199be87d1f790f0c82edf918d388c669f9be68b467f2
6
+ metadata.gz: bf3e8a28916019f60f64ce668cd919e4b59e3ebcb50e397266363b7f43d093cbefd06bb41b9816351b9435484b5948eaf5c45e5408d677d76c0ac879ae98b21e
7
+ data.tar.gz: b387b82d92712aba64d47e0a8ac33abc9789dba435e88e0020de6eae46881938fcdba5f16da39cbc3930e8a8e9b4bdacf3688388c9d328be25845915b341a5ce
data/README.md CHANGED
@@ -531,7 +531,7 @@ provides an easy way to get the semaphore key:
531
531
 
532
532
  ```
533
533
  irb> require 'semian'
534
- irb> puts Semian::Resource.new(:your_resource_name, tickets:1).key # do this from a dev machine
534
+ irb> puts Semian::Resource.new(:your_resource_name, tickets: 42).key # do this from a dev machine
535
535
  "0x48af51ea"
536
536
  ```
537
537
 
@@ -553,8 +553,8 @@ otime = Thu Mar 30 15:06:16 2017
553
553
  ctime = Mon Mar 13 20:25:36 2017
554
554
  semnum value ncount zcount pid
555
555
  0 1 0 0 48
556
- 1 25 0 0 48
557
- 2 25 0 0 27
556
+ 1 42 0 0 48
557
+ 2 42 0 0 27
558
558
  3 31 0 0 48
559
559
  ```
560
560
 
data/lib/semian/mysql2.rb CHANGED
@@ -43,16 +43,18 @@ module Semian
43
43
  %r{\A(?:/\*.*?\*/)?\s*RELEASE\s+SAVEPOINT}i,
44
44
  )
45
45
 
46
- # The naked methods are exposed as `raw_query` and `raw_connect` for instrumentation purpose
47
- def self.included(base)
48
- base.send(:alias_method, :raw_query, :query)
49
- base.send(:remove_method, :query)
46
+ class << self
47
+ # The naked methods are exposed as `raw_query` and `raw_connect` for instrumentation purpose
48
+ def included(base)
49
+ base.send(:alias_method, :raw_query, :query)
50
+ base.send(:remove_method, :query)
50
51
 
51
- base.send(:alias_method, :raw_connect, :connect)
52
- base.send(:remove_method, :connect)
52
+ base.send(:alias_method, :raw_connect, :connect)
53
+ base.send(:remove_method, :connect)
53
54
 
54
- base.send(:alias_method, :raw_ping, :ping)
55
- base.send(:remove_method, :ping)
55
+ base.send(:alias_method, :raw_ping, :ping)
56
+ base.send(:remove_method, :ping)
57
+ end
56
58
  end
57
59
 
58
60
  def semian_identifier
@@ -68,6 +70,8 @@ module Semian
68
70
  end
69
71
 
70
72
  def ping
73
+ return false if closed?
74
+
71
75
  result = nil
72
76
  acquire_semian_resource(adapter: :mysql, scope: :ping) do
73
77
  result = raw_ping
data/lib/semian/rails.rb CHANGED
@@ -4,6 +4,23 @@ require "active_record/connection_adapters/abstract_adapter"
4
4
 
5
5
  module Semian
6
6
  module Rails
7
+ extend ActiveSupport::Concern
8
+
9
+ module ClassMethods
10
+ # Translate ConnectionNotEstablished errors to their original
11
+ # cause if applicable. When we have a CircuitOpenErorr we don't
12
+ # want the Active Record error, but rather the original cause.
13
+ def new_client(config)
14
+ super
15
+ rescue ActiveRecord::ConnectionNotEstablished => e
16
+ if e.cause.is_a?(Mysql2::CircuitOpenError)
17
+ raise e.cause
18
+ else
19
+ raise
20
+ end
21
+ end
22
+ end
23
+
7
24
  def semian_resource
8
25
  @semian_resource ||= client_connection.semian_resource
9
26
  end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "semian/redis_client"
4
+
5
+ class Redis
6
+ BaseConnectionError.include(::Semian::AdapterError)
7
+ OutOfMemoryError.include(::Semian::AdapterError)
8
+
9
+ class SemianError < BaseConnectionError
10
+ def initialize(semian_identifier, *args)
11
+ super(*args)
12
+ @semian_identifier = semian_identifier
13
+ end
14
+ end
15
+
16
+ ResourceBusyError = Class.new(SemianError)
17
+ CircuitOpenError = Class.new(SemianError)
18
+
19
+ Client::ERROR_MAPPING.merge!(
20
+ RedisClient::CircuitOpenError => Redis::CircuitOpenError,
21
+ RedisClient::ResourceBusyError => Redis::ResourceBusyError,
22
+ )
23
+ end
24
+
25
+ module Semian
26
+ module RedisV5
27
+ def semian_resource
28
+ _client.semian_resource
29
+ end
30
+
31
+ def semian_identifier
32
+ _client.semian_identifier
33
+ end
34
+ end
35
+
36
+ module RedisV5Client
37
+ private
38
+
39
+ def translate_error!(error)
40
+ redis_error = translate_error_class(error.class)
41
+ if redis_error < ::Semian::AdapterError
42
+ redis_error = redis_error.new(error.message)
43
+ redis_error.semian_identifier = semian_identifier
44
+ end
45
+ raise redis_error, error.message, error.backtrace
46
+ end
47
+ end
48
+ end
49
+
50
+ ::Redis.prepend(Semian::RedisV5)
51
+ ::Redis::Client.prepend(Semian::RedisV5Client)
data/lib/semian/redis.rb CHANGED
@@ -3,6 +3,12 @@
3
3
  require "semian/adapter"
4
4
  require "redis"
5
5
 
6
+ if Redis::VERSION >= "5"
7
+ gem "redis", ">= 5.0.3"
8
+ require "semian/redis/v5"
9
+ return
10
+ end
11
+
6
12
  class Redis
7
13
  Redis::BaseConnectionError.include(::Semian::AdapterError)
8
14
  ::Errno::EINVAL.include(::Semian::AdapterError)
@@ -58,20 +64,22 @@ class Redis
58
64
  end
59
65
 
60
66
  module Semian
61
- module Redis
67
+ module RedisV4
62
68
  include Semian::Adapter
63
69
 
64
70
  ResourceBusyError = ::Redis::ResourceBusyError
65
71
  CircuitOpenError = ::Redis::CircuitOpenError
66
72
  ResolveError = ::Redis::ResolveError
67
73
 
68
- # The naked methods are exposed as `raw_query` and `raw_connect` for instrumentation purpose
69
- def self.included(base)
70
- base.send(:alias_method, :raw_io, :io)
71
- base.send(:remove_method, :io)
74
+ class << self
75
+ # The naked methods are exposed as `raw_query` and `raw_connect` for instrumentation purpose
76
+ def included(base)
77
+ base.send(:alias_method, :raw_io, :io)
78
+ base.send(:remove_method, :io)
72
79
 
73
- base.send(:alias_method, :raw_connect, :connect)
74
- base.send(:remove_method, :connect)
80
+ base.send(:alias_method, :raw_connect, :connect)
81
+ base.send(:remove_method, :connect)
82
+ end
75
83
  end
76
84
 
77
85
  def semian_identifier
@@ -150,4 +158,4 @@ module Semian
150
158
  end
151
159
  end
152
160
 
153
- ::Redis::Client.include(Semian::Redis)
161
+ ::Redis::Client.include(Semian::RedisV4)
@@ -5,6 +5,14 @@ require "redis-client"
5
5
 
6
6
  class RedisClient
7
7
  ConnectionError.include(::Semian::AdapterError)
8
+ ConnectionError.class_eval do
9
+ # A Connection Reset is a fast failure and we don't want to track these errors in semian
10
+ def marks_semian_circuits?
11
+ !message.include?("Connection reset by peer")
12
+ end
13
+ end
14
+
15
+ OutOfMemoryError.include(::Semian::AdapterError)
8
16
 
9
17
  class SemianError < ConnectionError
10
18
  def initialize(semian_identifier, *args)
@@ -72,7 +80,7 @@ module Semian
72
80
  end
73
81
 
74
82
  module RedisClient
75
- EXCEPTIONS = [::RedisClient::ConnectionError]
83
+ EXCEPTIONS = [::RedisClient::ConnectionError, ::RedisClient::OutOfMemoryError]
76
84
 
77
85
  include Semian::Adapter
78
86
  include RedisClientCommon
@@ -110,4 +118,4 @@ module Semian
110
118
  end
111
119
 
112
120
  RedisClient.prepend(Semian::RedisClient)
113
- RedisClient::Pooled.prepend(Semian::RedisClient)
121
+ RedisClient::Pooled.prepend(Semian::RedisClientPool)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Semian
4
- VERSION = "0.13.2"
4
+ VERSION = "0.15.0"
5
5
  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.13.2
4
+ version: 0.15.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Scott Francis
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2022-08-19 00:00:00.000000000 Z
13
+ date: 2022-09-12 00:00:00.000000000 Z
14
14
  dependencies: []
15
15
  description: |2
16
16
  A Ruby C extention that is used to control access to shared resources
@@ -21,7 +21,6 @@ extensions:
21
21
  - ext/semian/extconf.rb
22
22
  extra_rdoc_files: []
23
23
  files:
24
- - CHANGELOG.md
25
24
  - LICENSE.md
26
25
  - README.md
27
26
  - ext/semian/extconf.rb
@@ -46,6 +45,7 @@ files:
46
45
  - lib/semian/protected_resource.rb
47
46
  - lib/semian/rails.rb
48
47
  - lib/semian/redis.rb
48
+ - lib/semian/redis/v5.rb
49
49
  - lib/semian/redis_client.rb
50
50
  - lib/semian/resource.rb
51
51
  - lib/semian/simple_integer.rb
@@ -60,6 +60,8 @@ metadata:
60
60
  allowed_push_host: https://rubygems.org
61
61
  bug_tracker_uri: https://github.com/Shopify/semian/issues
62
62
  changelog_uri: https://github.com/Shopify/semian/blob/master/CHANGELOG.md
63
+ documentation_uri: https://github.com/Shopify/semian
64
+ homepage_uri: https://github.com/Shopify/semian
63
65
  source_code_uri: https://github.com/Shopify/semian
64
66
  post_install_message:
65
67
  rdoc_options: []
data/CHANGELOG.md DELETED
@@ -1,243 +0,0 @@
1
- # Unreleased
2
-
3
- # v0.13.2
4
-
5
- * Fix: Update AbstractAdapter patch to accomodate recent Rails changes. (#364)
6
-
7
- # v0.13.1
8
-
9
- * Fix: Raise `Redis::OutOfMemoryError` for messages that match `OOM command not allowed when used memory > 'maxmemory'` rather than checking `start_with?("OOM ")`. (#367)
10
-
11
- # v0.13.0
12
-
13
- * Refactor: Replace Time.now with CLOCK_MONOTONIC in MockServer (#318)
14
- * Fix: Circuit not open for GRPC::ActiveCall::Operation failures (#348)
15
-
16
- # v0.12.0
17
-
18
- * Feature: Add support for the `redis-client` gem (#314)
19
-
20
- # v0.11.8
21
-
22
- * Feature: Add error_threshold_timeout configuration parameter (#299)
23
-
24
- # v0.11.7
25
-
26
- * Fix: ECONNRESET won't trigger circuit open for redis (#306)
27
-
28
- # v0.11.6
29
-
30
- * Fix: pass disable flag by patching new singleton method (#303)
31
-
32
- # v0.11.5
33
-
34
- * Feature: Add disable flag to http adapter (#301)
35
-
36
- # v0.11.4
37
-
38
- * Fix: Add `extern` to global variable declarations for gcc 10 (#288)
39
-
40
- # v0.11.3
41
-
42
- * Feature: Log last error message on circuit breaker state transition (#285)
43
- * Fix: Update README and docs to resolve common misconception about error_threshold (#283)
44
-
45
- # v0.11.2
46
-
47
- * Fix: Remove `MySQL client is not connected` error from mysql2 adapter
48
-
49
- # v0.11.1
50
-
51
- * Feature: Add `Semian.namespace` to globally prefix all the semaphore names. (#280)
52
-
53
- # v0.11.0
54
-
55
- * Feature: Add `Semian.default_permissions` to globally change the default semaphore permissions. (#279)
56
-
57
- # v0.10.6
58
-
59
- * Fix: Match whitelisted SQL queries when Marginalia is prepended (#276)
60
-
61
- # v0.10.5
62
-
63
- * Fix: Compatibility with GC.compact
64
-
65
- # v0.10.4
66
-
67
- * Fix: Revert the changes in v0.10.3. (#270)
68
-
69
- # v0.10.3
70
-
71
- * Fix: Positional/Keyword arguments deprecations warning for Ruby 2.7 in the grpc adapter. (#269)
72
-
73
- # v0.10.2
74
-
75
- * Fix: Positional/Keyword arguments deprecations warning for Ruby 2.7.
76
-
77
- # v0.10.1
78
-
79
- * Fix: thread safety bug on Ruby 2.7. (#263)
80
-
81
- # v0.10.0
82
-
83
- * Feature: Support half open resource timeout for redis.
84
-
85
- # v0.9.1
86
-
87
- * Fix: Compatibility with MRI 2.3
88
-
89
- # v0.9.0
90
-
91
- * Feature: Add a LRU to garbage collect old resources. (#193)
92
-
93
- # v0.8.9
94
- * Fix: Recursion issue in MySQL2 adapter causing circuits breakers to stay open much longer than they should. (#250)
95
- * Fix: Better handle DNS resolutions exceptions in Redis adapter. (#230)
96
-
97
- # v0.8.8
98
- * Feature: Introduce the GRPC adapter (#200)
99
-
100
- # v0.8.7
101
- * Fix: Instrument success for `acquire_circuit_breaker` (#209)
102
-
103
- # v0.8.6
104
- * Feature: If an error instance responds to `#marks_semian_circuits?` don't mark the circuit if it returns false (#210)
105
-
106
- # v0.8.5
107
- * Fix: Redis adapter using hiredis is resilient to DNS resolution failures (#205)
108
-
109
- # v0.8.4
110
- * Feature: Introduce `half_open_resource_timeout` which changes the resource timeout when the circuit is in a half-open state for the Net::HTTP adapter. (#198)
111
- * Feature: Add the cause of the last error when a circuit opens (#197)
112
- * Fix: Reset successes when transitioning to the half open state (#192)
113
-
114
- # v0.8.1
115
-
116
- * Fix: Expose `half_open?` when the circuit state has not transitioned but will. This allows consumers further up the stack to know if the circuit
117
- is half open.
118
-
119
- # v0.8.0
120
-
121
- * Feature: Introduce `half_open_resource_timeout` which changes the resource timeout when the circuit is in a half-open state (#188)
122
-
123
- # v0.7.8
124
-
125
- * Feature: More informative error messages when initializing Semian with missing
126
- arguments (#182)
127
- * Fix: Redis adapter is now resilient to DNS resolution failures (#184)
128
-
129
- # v0.7.5
130
-
131
- * Fix: Repaired compatibility with dependent Redis library
132
-
133
- # v0.7.4
134
-
135
- * Fix: Protect internal semaphore when adjusting resource count (#164)
136
- * Feature: Use prepend when monkey-patching Net::HTTP. (#157)
137
- * Feature: Include time spend waiting for bulkhead in notification (#154)
138
-
139
- # v0.7.1
140
-
141
- * Feature: Add the behaviour to enable open circuiting on 5xxs conditionally (#149)
142
- * Refactor: Configurable hosts for Semian's development dependencies (#152)
143
-
144
- # v0.7.0
145
-
146
- This change introduced a series of changes to support a new "dynamic quota" ticket
147
- allocation strategy. This code primarily affects bulkheads (protected resources).
148
-
149
- Rather than statically setting a ticket count, workers (in their own process) now register
150
- themselves. By specifying 'quota' instead of 'tickets', the bulkhead threshold will now be
151
- computed dynamically as a ratio of the number of registered workers, eliminating the need to
152
- continuously readjust ticket counts, and supporting environments with non-uniform worker
153
- distribution between machines.
154
-
155
- * Feature: Support quota based allocation strategy (#120)
156
- * Feature: Add ability to manually unregister workers (#130)
157
- * Feature: Add ability to clear resources from adapters and unregister all resources (#134)
158
- * Feature: Allow sysV IPC key to be accessed in ruby (#136)
159
- * Feature: Expose registered worker count to ruby (#137)
160
- * Refactor: Allow registered worker count to be accessed through bulkhead (#138)
161
- * Bug fix: Register all workers (#128)
162
- * Bug fix: Lazy instantiate redis clien on first I/O (#132)
163
- * Bug fix: New mysql error (#131)
164
- * Bug fix: Prevent race conditions when unregistering (#141)
165
- * Refactor/Feature: Break coupling between resource and circuit breaker (#123)
166
- * Refactor: Use generic max_sem_val (#117)
167
- * Refactor: Fix header syntax (#118)
168
- * Refactor: Always acquire semaphore without_gvl (#121)
169
- * Thread-safety for circuit breakers by default (#150)
170
- * Fix bug where calling name on a protected resource without a semaphore would fail (#151)
171
-
172
- # v0.6.2
173
-
174
- * Refactor: Refactor semian ticket management into its own files (#116)
175
- * Refactor: Create sem_meta_lock and sem_meta_unlock (#115)
176
- * Refactor: Refactor semaphore operations (#114)
177
-
178
- # v0.6.1
179
-
180
- * Refactor: Generate a unique semaphore key by including size of semaphore set
181
- * Refactor: Refactor semian\_resource related C functions
182
- * Fix: Don't require sudo for travis (#110)
183
- * Refactor: Refactor semian.c includes and types into header files
184
- * Fix: Use glob instead of git for gemspec file list
185
- * Fix: Fix travis CI for ruby 2.3.0 installing rainbows
186
- * Refactor: Switch to enumerated type for tracking semaphore indices
187
- * Docs: readme: explain co-operation between cbs and bulkheads
188
- * Docs: readme: add section about server limits
189
-
190
- # v0.6.0
191
-
192
- * Feature: Load semian/rails automatically if necessary
193
- * Feature: Implement AR::AbstractAdapter#semian\_resource
194
-
195
- # v0.5.4
196
-
197
- * Fix: Also let "Too many connections" be a first class conn error
198
-
199
- # v0.5.3
200
-
201
- * Fix: mysql: protect pings
202
- * Fix: mysql: match more lost conn queries
203
-
204
- # v0.5.2
205
-
206
- * Fix: Make request\_allowed? thread safe
207
- * Fix: Fix CI connect errors on HTTP requests by using 127.0.0.1 for host
208
-
209
- # v0.5.1
210
-
211
- * Fix: Assert Resource#initialize\_semaphore contract on Resource init
212
- * Fix: Lock on older thin version for pre MRI 2.2 compatibility
213
-
214
- # v0.5.0
215
-
216
- * Fix: Only issue unsupported or disabled semaphores warnings when the first resource is instanciated
217
- * Refactor: Cleanup requires
218
- * Maintenance: Use published version of the toxiproxy gem
219
- * Fix: Fix minitest deprecation warnings
220
- * Maintenance: Update bundler on travis
221
- * Maintenance: Update supported MRI versions on travis
222
-
223
- # v0.4.3
224
-
225
- * Fix: Fix lazy aliasing of Redis#semian\_resource
226
- * Fix: Workaround rubocop parser limitations
227
-
228
- # v0.4.2
229
-
230
- * Fix: Fix for TimeoutError is deprecated in Ruby 2.3.0
231
- * Feature: Include Ruby 2.3 in Travis builds
232
-
233
- # v0.4.1
234
- * Fix: resource: cast float ticket count to fixnum #75
235
-
236
- # v0.4.0
237
-
238
- * Feature: net/http: add adapter for net/http #58
239
- * Refactor: circuit_breaker: split circuit breaker into three data structures to allow for
240
- alternative implementations in the future #62
241
- * Fix: mysql: don't prevent rollbacks on transactions #60
242
- * Fix: core: fix initialization bug when the resource is accessed before the options
243
- are set #65