semian 0.11.9 → 0.13.1

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.
@@ -1,33 +1,35 @@
1
- $LOAD_PATH.unshift File.expand_path("../../../lib", __FILE__)
1
+ # frozen_string_literal: true
2
2
 
3
- require 'semian/platform'
3
+ $LOAD_PATH.unshift(File.expand_path("../../../lib", __FILE__))
4
+
5
+ require "semian/platform"
4
6
 
5
7
  unless Semian.sysv_semaphores_supported?
6
- File.write "Makefile", <<MAKEFILE
7
- all:
8
- clean:
9
- install:
10
- MAKEFILE
8
+ File.write("Makefile", <<~MAKEFILE)
9
+ all:
10
+ clean:
11
+ install:
12
+ MAKEFILE
11
13
  exit
12
14
  end
13
15
 
14
- require 'mkmf'
16
+ require "mkmf"
15
17
 
16
- abort 'openssl is missing. please install openssl.' unless find_header('openssl/sha.h')
17
- abort 'openssl is missing. please install openssl.' unless find_library('crypto', 'SHA1')
18
+ abort "openssl is missing. please install openssl." unless find_header("openssl/sha.h")
19
+ abort "openssl is missing. please install openssl." unless find_library("crypto", "SHA1")
18
20
 
19
- have_header 'sys/ipc.h'
20
- have_header 'sys/sem.h'
21
- have_header 'sys/types.h'
21
+ have_header "sys/ipc.h"
22
+ have_header "sys/sem.h"
23
+ have_header "sys/types.h"
22
24
 
23
- have_func 'rb_thread_blocking_region'
24
- have_func 'rb_thread_call_without_gvl'
25
+ have_func "rb_thread_blocking_region"
26
+ have_func "rb_thread_call_without_gvl"
25
27
 
26
28
  $CFLAGS = "-D_GNU_SOURCE -Werror -Wall "
27
- if ENV.key?('DEBUG')
28
- $CFLAGS << "-O0 -g -DDEBUG"
29
+ $CFLAGS += if ENV.key?("DEBUG")
30
+ "-O0 -g -DDEBUG"
29
31
  else
30
- $CFLAGS << "-O3"
32
+ "-O3"
31
33
  end
32
34
 
33
- create_makefile('semian/semian')
35
+ create_makefile("semian/semian")
@@ -1,9 +1,11 @@
1
- require 'semian'
1
+ # frozen_string_literal: true
2
+
3
+ require "semian"
2
4
 
3
5
  module Semian
4
6
  module Adapter
5
7
  def semian_identifier
6
- raise NotImplementedError.new("Semian adapters must implement a `semian_identifier` method")
8
+ raise NotImplementedError, "Semian adapters must implement a `semian_identifier` method"
7
9
  end
8
10
 
9
11
  def semian_resource
@@ -31,6 +33,7 @@ module Semian
31
33
 
32
34
  def acquire_semian_resource(scope:, adapter:, &block)
33
35
  return yield if resource_already_acquired?
36
+
34
37
  semian_resource.acquire(scope: scope, adapter: adapter, resource: self) do
35
38
  mark_resource_as_acquired(&block)
36
39
  end
@@ -48,16 +51,17 @@ module Semian
48
51
 
49
52
  def semian_options
50
53
  return @semian_options if defined? @semian_options
54
+
51
55
  options = raw_semian_options
52
56
  @semian_options = options && options.map { |k, v| [k.to_sym, v] }.to_h
53
57
  end
54
58
 
55
59
  def raw_semian_options
56
- raise NotImplementedError.new("Semian adapters must implement a `raw_semian_options` method")
60
+ raise NotImplementedError, "Semian adapters must implement a `raw_semian_options` method"
57
61
  end
58
62
 
59
63
  def resource_exceptions
60
- []
64
+ raise NotImplementedError, "Semian adapters must implement a `resource_exceptions` method"
61
65
  end
62
66
 
63
67
  def resource_already_acquired?
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Semian
2
- class CircuitBreaker #:nodoc:
4
+ class CircuitBreaker # :nodoc:
3
5
  extend Forwardable
4
6
 
5
7
  def_delegators :@state, :closed?, :open?, :half_open?
@@ -7,7 +9,9 @@ module Semian
7
9
  attr_reader :name, :half_open_resource_timeout, :error_timeout, :state, :last_error
8
10
 
9
11
  def initialize(name, exceptions:, success_threshold:, error_threshold:,
10
- error_timeout:, implementation:, half_open_resource_timeout: nil, error_threshold_timeout: nil)
12
+ error_timeout:, implementation:, half_open_resource_timeout: nil,
13
+ error_threshold_timeout: nil)
14
+
11
15
  @name = name.to_sym
12
16
  @success_count_threshold = success_threshold
13
17
  @error_count_threshold = error_threshold
@@ -25,6 +29,7 @@ module Semian
25
29
 
26
30
  def acquire(resource = nil, &block)
27
31
  return yield if disabled?
32
+
28
33
  transition_to_half_open if transition_to_half_open?
29
34
 
30
35
  raise OpenCircuitError unless request_allowed?
@@ -63,6 +68,7 @@ module Semian
63
68
 
64
69
  def mark_success
65
70
  return unless half_open?
71
+
66
72
  @successes.increment
67
73
  transition_to_close if success_threshold_reached?
68
74
  end
@@ -80,8 +86,7 @@ module Semian
80
86
  end
81
87
 
82
88
  def in_use?
83
- return false if error_timeout_expired?
84
- @errors.size > 0
89
+ !error_timeout_expired? && !@errors.empty?
85
90
  end
86
91
 
87
92
  private
@@ -117,6 +122,7 @@ module Semian
117
122
  def error_timeout_expired?
118
123
  last_error_time = @errors.last
119
124
  return false unless last_error_time
125
+
120
126
  Time.at(last_error_time) + @error_timeout < Time.now
121
127
  end
122
128
 
@@ -133,12 +139,12 @@ module Semian
133
139
  return if @state.nil? || new_state == @state.value
134
140
 
135
141
  str = "[#{self.class.name}] State transition from #{@state.value} to #{new_state}."
136
- str << " success_count=#{@successes.value} error_count=#{@errors.size}"
137
- str << " success_count_threshold=#{@success_count_threshold} error_count_threshold=#{@error_count_threshold}"
138
- str << " error_timeout=#{@error_timeout} error_last_at=\"#{@errors.last}\""
139
- str << " name=\"#{@name}\""
142
+ str += " success_count=#{@successes.value} error_count=#{@errors.size}"
143
+ str += " success_count_threshold=#{@success_count_threshold} error_count_threshold=#{@error_count_threshold}"
144
+ str += " error_timeout=#{@error_timeout} error_last_at=\"#{@errors.last}\""
145
+ str += " name=\"#{@name}\""
140
146
  if new_state == :open && @last_error
141
- str << " last_error_message=#{@last_error.message.inspect}"
147
+ str += " last_error_message=#{@last_error.message.inspect}"
142
148
  end
143
149
 
144
150
  Semian.logger.info(str)
@@ -149,7 +155,7 @@ module Semian
149
155
  end
150
156
 
151
157
  def disabled?
152
- ENV['SEMIAN_CIRCUIT_BREAKER_DISABLED'] || ENV['SEMIAN_DISABLED']
158
+ ENV["SEMIAN_CIRCUIT_BREAKER_DISABLED"] || ENV["SEMIAN_DISABLED"]
153
159
  end
154
160
 
155
161
  def maybe_with_half_open_resource_timeout(resource, &block)
data/lib/semian/grpc.rb CHANGED
@@ -1,5 +1,7 @@
1
- require 'semian/adapter'
2
- require 'grpc'
1
+ # frozen_string_literal: true
2
+
3
+ require "semian/adapter"
4
+ require "grpc"
3
5
 
4
6
  module GRPC
5
7
  GRPC::Unavailable.include(::Semian::AdapterError)
@@ -22,7 +24,6 @@ end
22
24
 
23
25
  module Semian
24
26
  module GRPC
25
- attr_reader :raw_semian_options
26
27
  include Semian::Adapter
27
28
 
28
29
  ResourceBusyError = ::GRPC::ResourceBusyError
@@ -40,6 +41,7 @@ module Semian
40
41
 
41
42
  def semian_configuration=(configuration)
42
43
  raise Semian::GRPC::SemianConfigurationChangedError unless @semian_configuration.nil?
44
+
43
45
  @semian_configuration = configuration
44
46
  end
45
47
 
@@ -52,10 +54,10 @@ module Semian
52
54
  @raw_semian_options ||= begin
53
55
  # If the host is empty, it's possible that the adapter was initialized
54
56
  # with the channel. Therefore, we look into the channel to find the host
55
- if @host.empty?
56
- host = @ch.target
57
+ host = if @host.empty?
58
+ @ch.target
57
59
  else
58
- host = @host
60
+ @host
59
61
  end
60
62
  @raw_semian_options = Semian::GRPC.retrieve_semian_configuration(host)
61
63
  @raw_semian_options = @raw_semian_options.dup unless @raw_semian_options.nil?
@@ -81,22 +83,42 @@ module Semian
81
83
 
82
84
  def request_response(*, **)
83
85
  return super if disabled?
84
- acquire_semian_resource(adapter: :grpc, scope: :request_response) { super }
86
+
87
+ acquire_semian_resource_grpc(scope: :request_response) { super }
85
88
  end
86
89
 
87
90
  def client_streamer(*, **)
88
91
  return super if disabled?
89
- acquire_semian_resource(adapter: :grpc, scope: :client_streamer) { super }
92
+
93
+ acquire_semian_resource_grpc(scope: :client_streamer) { super }
90
94
  end
91
95
 
92
96
  def server_streamer(*, **)
93
97
  return super if disabled?
94
- acquire_semian_resource(adapter: :grpc, scope: :server_streamer) { super }
98
+
99
+ acquire_semian_resource_grpc(scope: :server_streamer) { super }
95
100
  end
96
101
 
97
102
  def bidi_streamer(*, **)
98
103
  return super if disabled?
99
- acquire_semian_resource(adapter: :grpc, scope: :bidi_streamer) { super }
104
+
105
+ acquire_semian_resource_grpc(scope: :bidi_streamer) { super }
106
+ end
107
+
108
+ def acquire_semian_resource_grpc(scope:)
109
+ acquire_semian_resource(adapter: :grpc, scope: scope) do
110
+ result = yield
111
+ handle_operation(result, scope) if result.is_a?(::GRPC::ActiveCall::Operation)
112
+ result
113
+ end
114
+ end
115
+
116
+ def handle_operation(operation, scope)
117
+ execute = operation.singleton_method(:execute)
118
+ operation.instance_variable_set(:@semian, self)
119
+ operation.define_singleton_method(:execute) do
120
+ @semian.send(:acquire_semian_resource, **{ adapter: :grpc, scope: scope }) { execute.call }
121
+ end
100
122
  end
101
123
  end
102
124
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Semian
2
4
  module Instrumentable
3
5
  def subscribe(name = rand, &block)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class LRUHash
2
4
  # This LRU (Least Recently Used) hash will allow
3
5
  # the cleaning of resources as time goes on.
@@ -120,10 +122,10 @@ class LRUHash
120
122
 
121
123
  def clear_unused_resources
122
124
  payload = {
123
- size: @table.size,
124
- examined: 0,
125
- cleared: 0,
126
- elapsed: nil,
125
+ size: @table.size,
126
+ examined: 0,
127
+ cleared: 0,
128
+ elapsed: nil,
127
129
  }
128
130
  timer_start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
129
131
 
@@ -155,20 +157,19 @@ class LRUHash
155
157
  end
156
158
  end
157
159
 
158
- EXCEPTION_NEVER = {Exception => :never}.freeze
159
- EXCEPTION_IMMEDIATE = {Exception => :immediate}.freeze
160
+ EXCEPTION_NEVER = { Exception => :never }.freeze
161
+ EXCEPTION_IMMEDIATE = { Exception => :immediate }.freeze
160
162
  private_constant :EXCEPTION_NEVER
161
163
  private_constant :EXCEPTION_IMMEDIATE
162
164
 
163
- def try_synchronize
165
+ def try_synchronize(&block)
164
166
  Thread.handle_interrupt(EXCEPTION_NEVER) do
165
- begin
166
- return false unless @lock.try_lock
167
- Thread.handle_interrupt(EXCEPTION_IMMEDIATE) { yield }
168
- true
169
- ensure
170
- @lock.unlock if @lock.owned?
171
- end
167
+ return false unless @lock.try_lock
168
+
169
+ Thread.handle_interrupt(EXCEPTION_IMMEDIATE, &block)
170
+ true
171
+ ensure
172
+ @lock.unlock if @lock.owned?
172
173
  end
173
174
  end
174
175
  end
data/lib/semian/mysql2.rb CHANGED
@@ -1,5 +1,7 @@
1
- require 'semian/adapter'
2
- require 'mysql2'
1
+ # frozen_string_literal: true
2
+
3
+ require "semian/adapter"
4
+ require "mysql2"
3
5
 
4
6
  module Mysql2
5
7
  Mysql2::Error.include(::Semian::AdapterError)
@@ -32,13 +34,13 @@ module Semian
32
34
  CircuitOpenError = ::Mysql2::CircuitOpenError
33
35
  PingFailure = Class.new(::Mysql2::Error)
34
36
 
35
- DEFAULT_HOST = 'localhost'
37
+ DEFAULT_HOST = "localhost"
36
38
  DEFAULT_PORT = 3306
37
39
 
38
40
  QUERY_WHITELIST = Regexp.union(
39
- /\A(?:\/\*.*?\*\/)?\s*ROLLBACK/i,
40
- /\A(?:\/\*.*?\*\/)?\s*COMMIT/i,
41
- /\A(?:\/\*.*?\*\/)?\s*RELEASE\s+SAVEPOINT/i,
41
+ %r{\A(?:/\*.*?\*/)?\s*ROLLBACK}i,
42
+ %r{\A(?:/\*.*?\*/)?\s*COMMIT}i,
43
+ %r{\A(?:/\*.*?\*/)?\s*RELEASE\s+SAVEPOINT}i,
42
44
  )
43
45
 
44
46
  # The naked methods are exposed as `raw_query` and `raw_connect` for instrumentation purpose
@@ -55,7 +57,8 @@ module Semian
55
57
 
56
58
  def semian_identifier
57
59
  @semian_identifier ||= begin
58
- unless name = semian_options && semian_options[:name]
60
+ name = semian_options && semian_options[:name]
61
+ unless name
59
62
  host = query_options[:host] || DEFAULT_HOST
60
63
  port = query_options[:port] || DEFAULT_PORT
61
64
  name = "#{host}:#{port}"
@@ -68,7 +71,7 @@ module Semian
68
71
  result = nil
69
72
  acquire_semian_resource(adapter: :mysql, scope: :ping) do
70
73
  result = raw_ping
71
- raise PingFailure.new(result.to_s) unless result
74
+ raise PingFailure, result.to_s unless result
72
75
  end
73
76
  result
74
77
  rescue ResourceBusyError, CircuitOpenError, PingFailure
@@ -101,6 +104,11 @@ module Semian
101
104
 
102
105
  private
103
106
 
107
+ EXCEPTIONS = [].freeze
108
+ def resource_exceptions
109
+ EXCEPTIONS
110
+ end
111
+
104
112
  def query_whitelisted?(sql, *)
105
113
  QUERY_WHITELIST =~ sql
106
114
  rescue ArgumentError
@@ -108,6 +116,7 @@ module Semian
108
116
  # data that is not recognized as a valid encoding, in which case we just
109
117
  # return false.
110
118
  return false unless sql.valid_encoding?
119
+
111
120
  raise
112
121
  end
113
122
 
@@ -127,7 +136,7 @@ module Semian
127
136
 
128
137
  def raw_semian_options
129
138
  return query_options[:semian] if query_options.key?(:semian)
130
- return query_options['semian'.freeze] if query_options.key?('semian'.freeze)
139
+ return query_options["semian"] if query_options.key?("semian")
131
140
  end
132
141
  end
133
142
  end
@@ -1,5 +1,7 @@
1
- require 'semian/adapter'
2
- require 'net/http'
1
+ # frozen_string_literal: true
2
+
3
+ require "semian/adapter"
4
+ require "net/http"
3
5
 
4
6
  module Net
5
7
  ProtocolError.include(::Semian::AdapterError)
@@ -40,10 +42,11 @@ module Semian
40
42
  ::Net::ProtocolError,
41
43
  ::EOFError,
42
44
  ::IOError,
43
- ::SystemCallError, # includes ::Errno::EINVAL, ::Errno::ECONNRESET, ::Errno::ECONNREFUSED, ::Errno::ETIMEDOUT, and more
45
+ ::SystemCallError, # includes ::Errno::EINVAL, ::Errno::ECONNRESET,
46
+ # ::Errno::ECONNREFUSED, ::Errno::ETIMEDOUT, and more
44
47
  ].freeze # Net::HTTP can throw many different errors, this tries to capture most of them
45
48
 
46
- module ClassMethods
49
+ module ClassMethods
47
50
  def new(*args, semian: true)
48
51
  http = super(*args)
49
52
  http.instance_variable_set(:@semian_enabled, semian)
@@ -57,6 +60,7 @@ module Semian
57
60
 
58
61
  def semian_configuration=(configuration)
59
62
  raise Semian::NetHTTP::SemianConfigurationChangedError unless @semian_configuration.nil?
63
+
60
64
  @semian_configuration = configuration
61
65
  end
62
66
 
@@ -88,11 +92,13 @@ module Semian
88
92
 
89
93
  def connect
90
94
  return super if disabled?
95
+
91
96
  acquire_semian_resource(adapter: :http, scope: :connection) { super }
92
97
  end
93
98
 
94
99
  def transport_request(*)
95
100
  return super if disabled?
101
+
96
102
  acquire_semian_resource(adapter: :http, scope: :query) do
97
103
  handle_error_responses(super)
98
104
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Semian
2
4
  extend self
3
5
 
@@ -11,6 +13,6 @@ module Semian
11
13
  end
12
14
 
13
15
  def disabled?
14
- ENV['SEMIAN_SEMAPHORES_DISABLED'] || ENV['SEMIAN_DISABLED']
16
+ ENV["SEMIAN_SEMAPHORES_DISABLED"] || ENV["SEMIAN_DISABLED"]
15
17
  end
16
18
  end
@@ -1,10 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Semian
2
4
  class ProtectedResource
3
5
  extend Forwardable
4
6
 
5
7
  def_delegators :@bulkhead, :destroy, :count, :semid, :tickets, :registered_workers
6
8
  def_delegators :@circuit_breaker, :reset, :mark_failed, :mark_success, :request_allowed?,
7
- :open?, :closed?, :half_open?
9
+ :open?, :closed?, :half_open?
8
10
 
9
11
  attr_reader :bulkhead, :circuit_breaker, :name
10
12
  attr_accessor :updated_at
@@ -17,8 +19,8 @@ module Semian
17
19
  end
18
20
 
19
21
  def destroy
20
- @bulkhead.destroy unless @bulkhead.nil?
21
- @circuit_breaker.destroy unless @circuit_breaker.nil?
22
+ @bulkhead&.destroy
23
+ @circuit_breaker&.destroy
22
24
  end
23
25
 
24
26
  def acquire(timeout: nil, scope: nil, adapter: nil, resource: nil)
data/lib/semian/rails.rb CHANGED
@@ -1,9 +1,15 @@
1
- require 'active_record/connection_adapters/abstract_adapter'
1
+ # frozen_string_literal: true
2
2
 
3
- class ActiveRecord::ConnectionAdapters::AbstractAdapter
4
- def semian_resource
5
- # support for https://github.com/rails/rails/commit/d86fd6415c0dfce6fadb77e74696cf728e5eb76b
6
- connection = instance_variable_defined?(:@raw_connection) ? @raw_connection : @connection
7
- connection.semian_resource
3
+ require "active_record/connection_adapters/abstract_adapter"
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
12
+ end
13
+ end
8
14
  end
9
15
  end
data/lib/semian/redis.rb CHANGED
@@ -1,5 +1,7 @@
1
- require 'semian/adapter'
2
- require 'redis'
1
+ # frozen_string_literal: true
2
+
3
+ require "semian/adapter"
4
+ require "redis"
3
5
 
4
6
  class Redis
5
7
  Redis::BaseConnectionError.include(::Semian::AdapterError)
@@ -17,7 +19,7 @@ class Redis
17
19
  end
18
20
 
19
21
  class ConnectionError < Redis::BaseConnectionError
20
- # A Connection Reset is a fast failure and we don't want to track these errors in
22
+ # A Connection Reset is a fast failure and we don't want to track these errors in
21
23
  # semian
22
24
  def marks_semian_circuits?
23
25
  message != "Connection lost (ECONNRESET)"
@@ -90,12 +92,11 @@ module Semian
90
92
 
91
93
  def connect
92
94
  acquire_semian_resource(adapter: :redis, scope: :connection) do
93
- begin
94
- raw_connect
95
- rescue SocketError, RuntimeError => e
96
- raise ResolveError.new(semian_identifier) if dns_resolve_failure?(e.cause || e)
97
- raise
98
- end
95
+ raw_connect
96
+ rescue SocketError, RuntimeError => e
97
+ raise ResolveError, semian_identifier if dns_resolve_failure?(e.cause || e)
98
+
99
+ raise
99
100
  end
100
101
  end
101
102
 
@@ -107,7 +108,7 @@ module Semian
107
108
 
108
109
  begin
109
110
  connection.timeout = temp_timeout if connected?
110
- options[:timeout] = Float(temp_timeout),
111
+ options[:timeout] = Float(temp_timeout)
111
112
  options[:connect_timeout] = Float(temp_timeout)
112
113
  options[:read_timeout] = Float(temp_timeout)
113
114
  options[:write_timeout] = Float(temp_timeout)
@@ -133,17 +134,18 @@ module Semian
133
134
 
134
135
  def raw_semian_options
135
136
  return options[:semian] if options.key?(:semian)
136
- return options['semian'.freeze] if options.key?('semian'.freeze)
137
+ return options["semian"] if options.key?("semian")
137
138
  end
138
139
 
139
140
  def raise_if_out_of_memory(reply)
140
141
  return unless reply.is_a?(::Redis::CommandError)
141
- return unless reply.message =~ /OOM command not allowed when used memory > 'maxmemory'\.\s*\z/
142
- raise ::Redis::OutOfMemoryError.new(reply.message)
142
+ return unless reply.message =~ /OOM command not allowed when used memory > 'maxmemory'/
143
+
144
+ raise ::Redis::OutOfMemoryError, reply.message
143
145
  end
144
146
 
145
147
  def dns_resolve_failure?(e)
146
- e.to_s.match?(/(can't resolve)|(name or service not known)|(nodename nor servname provided, or not known)|(failure in name resolution)/i)
148
+ e.to_s.match?(/(can't resolve)|(name or service not known)|(nodename nor servname provided, or not known)|(failure in name resolution)/i) # rubocop:disable Layout/LineLength
147
149
  end
148
150
  end
149
151
  end
@@ -0,0 +1,113 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "semian/adapter"
4
+ require "redis-client"
5
+
6
+ class RedisClient
7
+ ConnectionError.include(::Semian::AdapterError)
8
+
9
+ class SemianError < ConnectionError
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
+ module SemianConfig
20
+ attr_reader :raw_semian_options
21
+
22
+ def initialize(semian: nil, **kwargs)
23
+ super(**kwargs)
24
+
25
+ @raw_semian_options = semian
26
+ end
27
+
28
+ def semian_identifier
29
+ @semian_identifier ||= begin
30
+ name = (semian_options && semian_options[:name]) || "#{host}:#{port}/#{db}"
31
+ :"redis_#{name}"
32
+ end
33
+ end
34
+
35
+ define_method(:semian_options, Semian::Adapter.instance_method(:semian_options))
36
+ end
37
+
38
+ Config.include(SemianConfig)
39
+ SentinelConfig.include(SemianConfig)
40
+ end
41
+
42
+ module Semian
43
+ module RedisClientCommon
44
+ def with_resource_timeout(temp_timeout)
45
+ connect_timeout = self.connect_timeout
46
+ read_timeout = self.read_timeout
47
+ write_timeout = self.write_timeout
48
+
49
+ begin
50
+ self.timeout = temp_timeout
51
+ yield
52
+ ensure
53
+ self.connect_timeout = connect_timeout
54
+ self.read_timeout = read_timeout
55
+ self.write_timeout = write_timeout
56
+ end
57
+ end
58
+
59
+ def semian_identifier
60
+ config.semian_identifier
61
+ end
62
+
63
+ private
64
+
65
+ def semian_options
66
+ config.semian_options
67
+ end
68
+
69
+ def raw_semian_options
70
+ config.raw_semian_options
71
+ end
72
+ end
73
+
74
+ module RedisClient
75
+ EXCEPTIONS = [::RedisClient::ConnectionError]
76
+
77
+ include Semian::Adapter
78
+ include RedisClientCommon
79
+
80
+ private
81
+
82
+ def resource_exceptions
83
+ EXCEPTIONS
84
+ end
85
+
86
+ def ensure_connected(retryable: true)
87
+ if block_given?
88
+ super do |connection|
89
+ acquire_semian_resource(adapter: :redis_client, scope: :query) do
90
+ yield connection
91
+ end
92
+ end
93
+ else
94
+ super
95
+ end
96
+ end
97
+
98
+ def connect
99
+ acquire_semian_resource(adapter: :redis_client, scope: :connection) do
100
+ super
101
+ end
102
+ end
103
+ end
104
+
105
+ module RedisClientPool
106
+ include RedisClientCommon
107
+ define_method(:semian_resource, Semian::Adapter.instance_method(:semian_resource))
108
+ define_method(:clear_semian_resource, Semian::Adapter.instance_method(:clear_semian_resource))
109
+ end
110
+ end
111
+
112
+ RedisClient.prepend(Semian::RedisClient)
113
+ RedisClient::Pooled.prepend(Semian::RedisClient)