semian 0.13.1 → 0.14.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 78f1c9a991cd16ae1da354babc364364cf1aac75f07b1fb3d694f75c94f33411
4
- data.tar.gz: 51585c1ccf8aa6f02c45b1da9da58753e91ce45a92f99c3880c5fb46c6b82aa5
3
+ metadata.gz: a7b62deafc4e8de524ae8aec32a17e3a1065d70206a5ead2ef6298da3b1c38ed
4
+ data.tar.gz: 3f6b18aa473410c0ad8d476931417fa69595328fd748a2edb75a333709b901cd
5
5
  SHA512:
6
- metadata.gz: 6b8f18a662e05dbedb5dec96ed1c740a40d1a644a098d01e0b82440aa6a877b9f3d67611cb38293699fb2a19bd4cf7aa9b0fa02c03babaa9063856d8cfabcd25
7
- data.tar.gz: 32546169e572cacd1cb85b63dd8b01164ba4eb15858394c9163d9de3d2ffdb258418f2dac7ebcb51e7ad8bd6ff592973c81f7758e8085a855b31011ce13c47e2
6
+ metadata.gz: c064829103c0c4f8915f6c072d43872b9a6dc011987e6a81f5efa8931052cc84b758df9bc4dd74f4f90c0501accbaa3e09ca3212af6a8a3e7056ce1f28a28e22
7
+ data.tar.gz: 124128fc2a5791317ea5a04b32c84e9b3cd394e843a74599c5ecf044cc6c89eec656384675b88e9fd73e95038dfb1e8a35b8e613034114e264b59e754a8eec0c
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
data/lib/semian/rails.rb CHANGED
@@ -2,14 +2,35 @@
2
2
 
3
3
  require "active_record/connection_adapters/abstract_adapter"
4
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
5
+ module Semian
6
+ module Rails
7
+ def semian_resource
8
+ @semian_resource ||= client_connection.semian_resource
9
+ end
10
+
11
+ def reconnect
12
+ @semian_resource = nil
13
+ super
14
+ end
15
+
16
+ private
17
+
18
+ # client_connection is an instance of a Mysql2::Client
19
+ #
20
+ # The conditionals here support multiple Rails versions.
21
+ # - valid_raw_connection is for 7.1.x and above
22
+ # - @raw_connection is for 7.0.x
23
+ # - @connection is for versions below 6.1.x and below
24
+ def client_connection
25
+ if respond_to?(:valid_raw_connection)
26
+ valid_raw_connection
27
+ elsif instance_variable_defined?(:@raw_connection)
28
+ @raw_connection
29
+ else
30
+ @connection
12
31
  end
13
32
  end
14
33
  end
15
34
  end
35
+
36
+ ActiveRecord::ConnectionAdapters::AbstractAdapter.prepend(Semian::Rails)
@@ -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.1"
4
+ VERSION = "0.14.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.1
4
+ version: 0.14.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-16 00:00:00.000000000 Z
13
+ date: 2022-09-07 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,239 +0,0 @@
1
- # Unreleased
2
-
3
- # v0.13.1
4
-
5
- * Fix: Raise `Redis::OutOfMemoryError` for messages that match `OOM command not allowed when used memory > 'maxmemory'` rather than checking `start_with?("OOM ")`. (#367)
6
-
7
- # v0.13.0
8
-
9
- * Refactor: Replace Time.now with CLOCK_MONOTONIC in MockServer (#318)
10
- * Fix: Circuit not open for GRPC::ActiveCall::Operation failures (#348)
11
-
12
- # v0.12.0
13
-
14
- * Feature: Add support for the `redis-client` gem (#314)
15
-
16
- # v0.11.8
17
-
18
- * Feature: Add error_threshold_timeout configuration parameter (#299)
19
-
20
- # v0.11.7
21
-
22
- * Fix: ECONNRESET won't trigger circuit open for redis (#306)
23
-
24
- # v0.11.6
25
-
26
- * Fix: pass disable flag by patching new singleton method (#303)
27
-
28
- # v0.11.5
29
-
30
- * Feature: Add disable flag to http adapter (#301)
31
-
32
- # v0.11.4
33
-
34
- * Fix: Add `extern` to global variable declarations for gcc 10 (#288)
35
-
36
- # v0.11.3
37
-
38
- * Feature: Log last error message on circuit breaker state transition (#285)
39
- * Fix: Update README and docs to resolve common misconception about error_threshold (#283)
40
-
41
- # v0.11.2
42
-
43
- * Fix: Remove `MySQL client is not connected` error from mysql2 adapter
44
-
45
- # v0.11.1
46
-
47
- * Feature: Add `Semian.namespace` to globally prefix all the semaphore names. (#280)
48
-
49
- # v0.11.0
50
-
51
- * Feature: Add `Semian.default_permissions` to globally change the default semaphore permissions. (#279)
52
-
53
- # v0.10.6
54
-
55
- * Fix: Match whitelisted SQL queries when Marginalia is prepended (#276)
56
-
57
- # v0.10.5
58
-
59
- * Fix: Compatibility with GC.compact
60
-
61
- # v0.10.4
62
-
63
- * Fix: Revert the changes in v0.10.3. (#270)
64
-
65
- # v0.10.3
66
-
67
- * Fix: Positional/Keyword arguments deprecations warning for Ruby 2.7 in the grpc adapter. (#269)
68
-
69
- # v0.10.2
70
-
71
- * Fix: Positional/Keyword arguments deprecations warning for Ruby 2.7.
72
-
73
- # v0.10.1
74
-
75
- * Fix: thread safety bug on Ruby 2.7. (#263)
76
-
77
- # v0.10.0
78
-
79
- * Feature: Support half open resource timeout for redis.
80
-
81
- # v0.9.1
82
-
83
- * Fix: Compatibility with MRI 2.3
84
-
85
- # v0.9.0
86
-
87
- * Feature: Add a LRU to garbage collect old resources. (#193)
88
-
89
- # v0.8.9
90
- * Fix: Recursion issue in MySQL2 adapter causing circuits breakers to stay open much longer than they should. (#250)
91
- * Fix: Better handle DNS resolutions exceptions in Redis adapter. (#230)
92
-
93
- # v0.8.8
94
- * Feature: Introduce the GRPC adapter (#200)
95
-
96
- # v0.8.7
97
- * Fix: Instrument success for `acquire_circuit_breaker` (#209)
98
-
99
- # v0.8.6
100
- * Feature: If an error instance responds to `#marks_semian_circuits?` don't mark the circuit if it returns false (#210)
101
-
102
- # v0.8.5
103
- * Fix: Redis adapter using hiredis is resilient to DNS resolution failures (#205)
104
-
105
- # v0.8.4
106
- * 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)
107
- * Feature: Add the cause of the last error when a circuit opens (#197)
108
- * Fix: Reset successes when transitioning to the half open state (#192)
109
-
110
- # v0.8.1
111
-
112
- * 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
113
- is half open.
114
-
115
- # v0.8.0
116
-
117
- * Feature: Introduce `half_open_resource_timeout` which changes the resource timeout when the circuit is in a half-open state (#188)
118
-
119
- # v0.7.8
120
-
121
- * Feature: More informative error messages when initializing Semian with missing
122
- arguments (#182)
123
- * Fix: Redis adapter is now resilient to DNS resolution failures (#184)
124
-
125
- # v0.7.5
126
-
127
- * Fix: Repaired compatibility with dependent Redis library
128
-
129
- # v0.7.4
130
-
131
- * Fix: Protect internal semaphore when adjusting resource count (#164)
132
- * Feature: Use prepend when monkey-patching Net::HTTP. (#157)
133
- * Feature: Include time spend waiting for bulkhead in notification (#154)
134
-
135
- # v0.7.1
136
-
137
- * Feature: Add the behaviour to enable open circuiting on 5xxs conditionally (#149)
138
- * Refactor: Configurable hosts for Semian's development dependencies (#152)
139
-
140
- # v0.7.0
141
-
142
- This change introduced a series of changes to support a new "dynamic quota" ticket
143
- allocation strategy. This code primarily affects bulkheads (protected resources).
144
-
145
- Rather than statically setting a ticket count, workers (in their own process) now register
146
- themselves. By specifying 'quota' instead of 'tickets', the bulkhead threshold will now be
147
- computed dynamically as a ratio of the number of registered workers, eliminating the need to
148
- continuously readjust ticket counts, and supporting environments with non-uniform worker
149
- distribution between machines.
150
-
151
- * Feature: Support quota based allocation strategy (#120)
152
- * Feature: Add ability to manually unregister workers (#130)
153
- * Feature: Add ability to clear resources from adapters and unregister all resources (#134)
154
- * Feature: Allow sysV IPC key to be accessed in ruby (#136)
155
- * Feature: Expose registered worker count to ruby (#137)
156
- * Refactor: Allow registered worker count to be accessed through bulkhead (#138)
157
- * Bug fix: Register all workers (#128)
158
- * Bug fix: Lazy instantiate redis clien on first I/O (#132)
159
- * Bug fix: New mysql error (#131)
160
- * Bug fix: Prevent race conditions when unregistering (#141)
161
- * Refactor/Feature: Break coupling between resource and circuit breaker (#123)
162
- * Refactor: Use generic max_sem_val (#117)
163
- * Refactor: Fix header syntax (#118)
164
- * Refactor: Always acquire semaphore without_gvl (#121)
165
- * Thread-safety for circuit breakers by default (#150)
166
- * Fix bug where calling name on a protected resource without a semaphore would fail (#151)
167
-
168
- # v0.6.2
169
-
170
- * Refactor: Refactor semian ticket management into its own files (#116)
171
- * Refactor: Create sem_meta_lock and sem_meta_unlock (#115)
172
- * Refactor: Refactor semaphore operations (#114)
173
-
174
- # v0.6.1
175
-
176
- * Refactor: Generate a unique semaphore key by including size of semaphore set
177
- * Refactor: Refactor semian\_resource related C functions
178
- * Fix: Don't require sudo for travis (#110)
179
- * Refactor: Refactor semian.c includes and types into header files
180
- * Fix: Use glob instead of git for gemspec file list
181
- * Fix: Fix travis CI for ruby 2.3.0 installing rainbows
182
- * Refactor: Switch to enumerated type for tracking semaphore indices
183
- * Docs: readme: explain co-operation between cbs and bulkheads
184
- * Docs: readme: add section about server limits
185
-
186
- # v0.6.0
187
-
188
- * Feature: Load semian/rails automatically if necessary
189
- * Feature: Implement AR::AbstractAdapter#semian\_resource
190
-
191
- # v0.5.4
192
-
193
- * Fix: Also let "Too many connections" be a first class conn error
194
-
195
- # v0.5.3
196
-
197
- * Fix: mysql: protect pings
198
- * Fix: mysql: match more lost conn queries
199
-
200
- # v0.5.2
201
-
202
- * Fix: Make request\_allowed? thread safe
203
- * Fix: Fix CI connect errors on HTTP requests by using 127.0.0.1 for host
204
-
205
- # v0.5.1
206
-
207
- * Fix: Assert Resource#initialize\_semaphore contract on Resource init
208
- * Fix: Lock on older thin version for pre MRI 2.2 compatibility
209
-
210
- # v0.5.0
211
-
212
- * Fix: Only issue unsupported or disabled semaphores warnings when the first resource is instanciated
213
- * Refactor: Cleanup requires
214
- * Maintenance: Use published version of the toxiproxy gem
215
- * Fix: Fix minitest deprecation warnings
216
- * Maintenance: Update bundler on travis
217
- * Maintenance: Update supported MRI versions on travis
218
-
219
- # v0.4.3
220
-
221
- * Fix: Fix lazy aliasing of Redis#semian\_resource
222
- * Fix: Workaround rubocop parser limitations
223
-
224
- # v0.4.2
225
-
226
- * Fix: Fix for TimeoutError is deprecated in Ruby 2.3.0
227
- * Feature: Include Ruby 2.3 in Travis builds
228
-
229
- # v0.4.1
230
- * Fix: resource: cast float ticket count to fixnum #75
231
-
232
- # v0.4.0
233
-
234
- * Feature: net/http: add adapter for net/http #58
235
- * Refactor: circuit_breaker: split circuit breaker into three data structures to allow for
236
- alternative implementations in the future #62
237
- * Fix: mysql: don't prevent rollbacks on transactions #60
238
- * Fix: core: fix initialization bug when the resource is accessed before the options
239
- are set #65