sc4ry 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,66 +1,63 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Sc4ry
2
- module Backends
3
- # Redis backend definition
4
- class Redis
4
+ module Backends
5
+ # Redis backend definition
6
+ class Redis
7
+ # Constructor
8
+ # @param [Hash] config Config map
9
+ # @return [Sc4ry::Backends::Redis] a Redis backend
10
+ def initialize(config)
11
+ @auth = config.slice(:auth)[:auth]
12
+ @config = config.slice(:host, :port, :db)
13
+ @be = ::Redis.new @config
14
+ @be.auth(@auth) if @auth
15
+ end
16
+
17
+ # return the list of find records in backend for a specific pattern
18
+ # @return [Array] list of record (for all hostname if hostname is specified)
19
+ def list
20
+ @be.keys('*').map(&:to_sym)
21
+ end
22
+
23
+ # return value of queried record
24
+ # @param key [Symbol] the name of the record
25
+ # @return [String] content value of record
26
+ def get(key:)
27
+ res = YAML.load(@be.get(key))
28
+ res[:exceptions].map! { |item| Object.const_get(item) if item.instance_of?(String) }
29
+ res
30
+ end
31
+
32
+ # defined and store value for specified key
33
+ # @param key [Symbol] :key the name of the record
34
+ # @param value [Symbol] :value the content value of the record
35
+ # @return [String] content value of record
36
+ def put(key:, value:)
37
+ data = value.dup
38
+ data[:exceptions].map! { |item| item.name.to_s if item.instance_of?(Class) }
39
+ @be.set key, data.to_yaml
40
+ end
41
+
42
+ # delete a specific record
43
+ # @param key [Symbol] the name of the record
44
+ # @return [Boolean] status of the operation
45
+ def del(key:)
46
+ @be.del key
47
+ end
48
+
49
+ # flush all records in backend
50
+ # @return [Boolean] status of the operation
51
+ def flush
52
+ @be.flushdb
53
+ end
5
54
 
6
- # Constructor
7
- # @param [Hash] config Config map
8
- # @return [Sc4ry::Backends::Redis] a Redis backend
9
- def initialize(config)
10
- @auth = config.slice(:auth)[:auth]
11
- @config = config.slice(:host, :port, :db)
12
- @be = ::Redis.new @config
13
- @be.auth(@auth) if @auth
14
- end
15
-
16
- # return the list of find records in backend for a specific pattern
17
- # @return [Array] list of record (for all hostname if hostname is specified)
18
- def list
19
- return @be.keys('*').map(&:to_sym)
20
- end
21
-
22
-
23
- # return value of queried record
24
- # @param key [Symbol] the name of the record
25
- # @return [String] content value of record
26
- def get(key:)
27
- res = YAML.load(@be.get(key))
28
- res[:exceptions].map! {|item| item = Object.const_get(item) if item.class == String }
29
- return res
30
- end
31
-
32
- # defined and store value for specified key
33
- # @param key [Symbol] :key the name of the record
34
- # @param value [Symbol] :value the content value of the record
35
- # @return [String] content value of record
36
- def put(key: ,value:)
37
- data = value.dup
38
- data[:exceptions].map! {|item| item = item.name.to_s if item.class == Class }
39
- @be.set key, data.to_yaml
40
- end
41
-
42
- # delete a specific record
43
- # @param key [Symbol] the name of the record
44
- # @return [Boolean] status of the operation
45
- def del(key: )
46
- @be.del key
47
- end
48
-
49
- # flush all records in backend
50
- # @return [Boolean] status of the operation
51
- def flush
52
- @be.flushdb
53
- end
54
-
55
- # verifiy a specific record existence
56
- # @param key [Symbol] the name of the record
57
- # @return [Boolean] presence of the record
58
- def exist?(key: )
59
- return ( not @be.get(key).nil?)
60
- end
61
-
62
-
55
+ # verifiy a specific record existence
56
+ # @param key [Symbol] the name of the record
57
+ # @return [Boolean] presence of the record
58
+ def exist?(key:)
59
+ !@be.get(key).nil?
63
60
  end
64
-
65
61
  end
66
- end
62
+ end
63
+ end
@@ -1,84 +1,81 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Sc4ry Module
2
4
  # @note namespace
3
5
  module Sc4ry
4
-
5
6
  # Circuits and default configuration management class
6
7
  class Circuits
7
-
8
8
  include Sc4ry::Constants
9
9
  include Sc4ry::Exceptions
10
10
 
11
- @@circuits_store = Sc4ry::Store.instance
11
+ @@circuits_store = Sc4ry::Store.instance
12
12
  @@circuits_notifiers = Sc4ry::Notifiers
13
13
  @@circuits_loggers = Sc4ry::Loggers
14
14
  @@config = DEFAULT_CONFIG
15
15
 
16
- # @!group forwarders
16
+ # @!group forwarders
17
17
 
18
18
  # Class method how forward the Notifiers class factory/manager
19
19
  # @return [Sc4ry::Notifiers]
20
- def Circuits.notifiers
21
- return @@circuits_notifiers
20
+ def self.notifiers
21
+ @@circuits_notifiers
22
22
  end
23
23
 
24
24
  # Class method how forward a Store manager class singleton
25
25
  # @return [Sc4ry::Store]
26
- def Circuits.store
27
- return @@circuits_store
26
+ def self.store
27
+ @@circuits_store
28
28
  end
29
29
 
30
30
  # Class method how forward the Logger manager class factory/manager
31
31
  # @return [Sc4ry::Store]
32
- def Circuits.loggers
33
- return @@circuits_loggers
32
+ def self.loggers
33
+ @@circuits_loggers
34
34
  end
35
35
 
36
-
37
-
38
36
  # @!endgroup
39
37
 
40
-
41
38
  # @!group Default Sc4ry configuration management
42
39
 
43
40
  # Class method how return de default Sc4ry config
44
- # @return [Hash]
45
- def Circuits.default_config
46
- return @@config
41
+ # @return [Hash]
42
+ def self.default_config
43
+ @@config
47
44
  end
48
45
 
49
46
  # class method how merge a differential hash to default config
50
47
  # @param [Hash] diff the differential hash config
51
48
  # @example usage
52
49
  # include Sc4ry
53
- # Circuits.merge_default_config diff: {max_time: 20, notifiers: [:mattermost]}
54
- def Circuits.merge_default_config(diff:)
55
- validator = Sc4ry::Config::Validator::new(definition: diff, from: @@config)
50
+ # Circuits.merge_default_config diff: {max_time: 20, notifiers: [:mattermost]}
51
+ def self.merge_default_config(diff:)
52
+ validator = Sc4ry::Config::Validator.new(definition: diff, from: @@config)
56
53
  validator.validate!
57
- @@config = validator.result
58
-
54
+ @@config = validator.result
59
55
  end
60
56
 
61
- # class method for specifiying config by block
57
+ # class method for specifiying config by block
62
58
  # @yield [Sc4ry::Config::ConfigMapper]
63
59
  # @example usage
64
60
  # include Sc4ry
65
61
  # Circuits.configure do |spec|
66
- # spec.max_failure_count = 3
62
+ # spec.max_failure_count = 3
67
63
  # end
68
- def Circuits.configure(&bloc)
69
- mapper = Sc4ry::Config::ConfigMapper::new(definition: @@config.dup)
64
+ def self.configure
65
+ mapper = Sc4ry::Config::ConfigMapper.new(definition: @@config.dup)
70
66
  yield(mapper)
71
- validator = Sc4ry::Config::Validator::new(definition: mapper.config, from: @@config)
67
+ validator = Sc4ry::Config::Validator.new(definition: mapper.config, from: @@config)
72
68
  validator.validate!
73
- @@config = validator.result
69
+ @@config = validator.result
74
70
  end
75
71
 
76
-
77
- # old default config setter
72
+ # old default config setter
78
73
  # @deprecated use {.merge_default_config} instead
79
74
  # @param [Hash] config
80
- def Circuits.default_config=(config)
81
- Sc4ry::Helpers.log level: :warn, message: "DEPRECATED: Circuits.default_config= is deprecated please use Circuits.merge_default_config add: {<config_hash>}"
75
+ def self.default_config=(config)
76
+ warning_mess = 'DEPRECATED: Circuits.default_config= use Circuits.merge_default_config add: {<config_hash>}'
77
+ Sc4ry::Helpers.log level: :warn,
78
+ message: warning_mess
82
79
  Circuits.merge_default_config(diff: config)
83
80
  end
84
81
 
@@ -91,77 +88,77 @@ module Sc4ry
91
88
  # @param [Symbol] circuit a circuit name
92
89
  # @param [Hash] config a config override on default config for the circuit
93
90
  # @example usage
94
- # include Sc4ry
91
+ # include Sc4ry
95
92
  # Circuits.register circuit: :mycircuit, config: {raise_on_opening: true, timeout: true}
96
93
  # # or
97
94
  # Circuits.register circuit: :mycircuit do |spec|
98
95
  # spec.raise_on_opening = true
99
96
  # spec.timeout = true
100
97
  # end
101
- # @return [Hash] the full config of the circuit after merge on default
98
+ # @return [Hash] the full config of the circuit after merge on default
102
99
  # @raise [Sc4ryGenericError] if use config keyword with a block
103
100
  # @raise [Sc4ryGenericError] if circuit already exist in current store.
104
- def Circuits.register(circuit:, config: {})
105
- if config.size > 0 and block_given? then
106
- raise Sc4ryGenericError, "config: keyword must not be defined when block is given"
101
+ def self.register(circuit:, config: {})
102
+ if !config.empty? && block_given?
103
+ raise Sc4ryGenericError,
104
+ 'config: keyword must not be defined when block is given'
107
105
  end
108
- if block_given? then
109
- mapper = Sc4ry::Config::ConfigMapper::new(definition: @@config.dup)
106
+
107
+ if block_given?
108
+ mapper = Sc4ry::Config::ConfigMapper.new(definition: @@config.dup)
110
109
  yield(mapper)
111
- validator = Sc4ry::Config::Validator::new(definition: mapper.config, from: @@config.dup)
112
- else
113
- validator = Sc4ry::Config::Validator::new(definition: config, from: @@config.dup )
110
+ validator = Sc4ry::Config::Validator.new(definition: mapper.config, from: @@config.dup)
111
+ else
112
+ validator = Sc4ry::Config::Validator.new(definition: config, from: @@config.dup)
114
113
  end
115
114
  validator.validate!
116
115
  Sc4ry::Helpers.log level: :debug, message: "Circuit #{circuit} : registered"
117
- raise Sc4ryGenericError, "Circuit: #{circuit} already exist in store" if @@circuits_store.exist? key: circuit
118
- @@circuits_store.put key: circuit, value: validator.result
119
- return validator.result
116
+ raise Sc4ryGenericError, "Circuit: #{circuit} already exist in store" if @@circuits_store.exist? key: circuit
117
+
118
+ @@circuits_store.put key: circuit, value: validator.result
119
+ validator.result
120
120
  end
121
121
 
122
122
  # class method how list all circuits in current store
123
123
  # @example usage
124
- # include Sc4ry
124
+ # include Sc4ry
125
125
  # circuits = Circuits.list
126
126
  # @return [Array] the list of [Symbol] circuits name
127
- def Circuits.list
128
- return @@circuits_store.list
127
+ def self.list
128
+ @@circuits_store.list
129
129
  end
130
130
 
131
131
  # class method how flush all circuits in current store
132
132
  # @example usage
133
- # include Sc4ry
133
+ # include Sc4ry
134
134
  # Circuits.flush
135
- # @return [true,false]
136
- def Circuits.flush
137
- return @@circuits_store.flush
135
+ # @return [true,false]
136
+ def self.flush
137
+ @@circuits_store.flush
138
138
  end
139
139
 
140
140
  # class method for unregistering a circuit
141
141
  # @param [Symbol] circuit a circuit name
142
142
  # @example usage
143
- # include Sc4ry
143
+ # include Sc4ry
144
144
  # Circuits.unregister circuit: :mycircuit
145
145
  # @raise [Sc4ryGenericError] if circuit not found in current store.
146
146
  # @return [true,false]
147
- def Circuits.unregister(circuit:)
148
- if Circuits.list.include? circuit then
149
- @@circuits_store.del key: circuit
150
- return true
151
- else
152
- raise Sc4ryGenericError, "Circuit #{circuit} not found"
153
- return false
154
- end
155
- end
147
+ def self.unregister(circuit:)
148
+ raise Sc4ryGenericError, "Circuit #{circuit} not found" unless Circuits.list.include? circuit
156
149
 
150
+ @@circuits_store.del key: circuit
151
+ Sc4ry::Helpers.log level: :debug, message: "Circuit #{circuit} : unregistered"
152
+ true
153
+ end
157
154
 
158
155
  # class method for get a specific circuit by circuit name
159
156
  # @param [Symbol] circuit a circuit name
160
157
  # @example usage
161
- # include Sc4ry
158
+ # include Sc4ry
162
159
  # Circuits.get circuit: :mycircuit
163
160
  # @return [Hash] the circuit record in current store included values and status if the circuit have already run.
164
- def Circuits.get(circuit:)
161
+ def self.get(circuit:)
165
162
  @@circuits_store.get key: circuit
166
163
  end
167
164
 
@@ -169,91 +166,93 @@ module Sc4ry
169
166
  # @param [Symbol] circuit a circuit name
170
167
  # @param [Hash] config a config hash to merge on current config
171
168
  # @example usage
172
- # include Sc4ry
169
+ # include Sc4ry
173
170
  # Circuits.update_config circuit: :mycircuit, config: {}
174
- # @note : <b>important</b> updating config will reset status and values !
171
+ # @note : <b>important</b> updating config will reset status and values !
175
172
  # @return [Hash] new config for this circuit
176
- def Circuits.update_config(circuit: , config: {forward_unknown_exceptions: false})
173
+ def self.update_config(circuit:, config: { forward_unknown_exceptions: false })
177
174
  raise Sc4ryGenericError, "Circuit #{circuit} not found" unless Circuits.list.include? circuit
175
+
178
176
  save = @@circuits_store.get key: circuit
179
- save.delete_if {|key,val| [:status,:values].include? key}
177
+ save.delete_if { |key, _val| %i[status values].include? key }
180
178
  Circuits.unregister(circuit: circuit)
181
179
  save.merge! config
182
- return Circuits.register circuit: circuit, config: save
180
+ Circuits.register circuit: circuit, config: save
183
181
  end
184
182
 
185
183
  # class method for get the status of a specific circuit by circuit name
186
184
  # @param [Symbol] circuit a circuit name
187
185
  # @example usage
188
- # include Sc4ry
186
+ # include Sc4ry
189
187
  # Circuits.status circuit: :mycircuit
190
- # @return [Symbol] status must in [:open,:half_open,:closed,:never_run]
191
- def Circuits.status(circuit:)
188
+ # @return [Symbol] status must in [:open,:half_open,:closed,:never_run]
189
+ def self.status(circuit:)
192
190
  data = @@circuits_store.get key: circuit
193
- return (data.include? :status)? data[:status][:general] : :never_run
191
+ data.include?(:status) ? data[:status][:general] : :never_run
194
192
  end
195
193
 
196
-
197
194
  # class method for running circuit, need a block
198
195
  # @yield [Proc]
199
196
  # @param [Symbol] circuit a circuit name
200
197
  # @example usage
201
- # include Sc4ry
202
- # Circuits.run circuit: :mycircuit do
198
+ # include Sc4ry
199
+ # Circuits.run circuit: :mycircuit do
203
200
  # # [...] your code like a Restclient.get("URL")
204
201
  # end
205
202
  # # or
206
- # Circuits.run do
203
+ # Circuits.run do
207
204
  # # [...] your code like a Restclient.get("URL")
208
205
  # # running with the first define circuit (use only on a one circuit usage)
209
206
  # end
210
207
  # @return [Hash] a result like ":general=>:open, :failure_count=>X, :overtime_count=>X, :timeout_count=>X"
211
- # @raise [Sc4ryGenericError] if circuit already not exit, block is missing or store empty
212
- def Circuits.run(circuit: nil , &block)
208
+ # @raise [Sc4ryGenericError] if circuit already not exit, block is missing or store empty
209
+ def self.run(circuit: nil, &block)
213
210
  circuits_list = Circuits.list
214
- raise Sc4ryGenericError, "No circuit block given" unless block_given?
215
- raise Sc4ryGenericError, "No circuits defined" if circuits_list.empty?
216
- circuit_name = (circuit)? circuit : circuits_list.first
211
+ raise Sc4ryGenericError, 'No circuit block given' unless block_given?
212
+ raise Sc4ryGenericError, 'No circuits defined' if circuits_list.empty?
213
+
214
+ circuit_name = circuit || circuits_list.first
217
215
  raise Sc4ryGenericError, "Circuit #{circuit_name} not found" unless circuits_list.include? circuit_name
216
+
218
217
  circuit_to_run = Circuits.get circuit: circuit_name
219
218
  skip = false
220
- if circuit_to_run.include? :status then
221
- if circuit_to_run[:status][:general] == :open then
222
- @now = Process.clock_gettime(Process::CLOCK_MONOTONIC)
223
- skip = true if ((@now - circuit_to_run[:values].last[:end_time]) < circuit_to_run[:check_delay])
224
- end
219
+ if circuit_to_run.include?(:status) && (circuit_to_run[:status][:general] == :open)
220
+ @now = Process.clock_gettime(Process::CLOCK_MONOTONIC)
221
+ skip = true if (@now - circuit_to_run[:values].last[:end_time]) < circuit_to_run[:check_delay]
225
222
  end
226
- unless skip
223
+ unless skip
227
224
  controller = Sc4ry::RunController.new(circuit_to_run)
228
225
  Circuits.control circuit: circuit_name, values: controller.run(block: block)
229
226
  end
230
227
  result = @@circuits_store.get key: circuit_name
231
228
  Sc4ry::Helpers.log level: :debug, message: "Circuit #{circuit_name} : status #{result[:status]}"
232
- return result
229
+ result
233
230
  end
234
231
 
235
232
  # @!endgroup
236
233
 
237
- private
238
234
  # the private class method to control circuits running status
239
235
  # @param [Symbol] circuit the name the circuit to control
240
- # @param [Hash] values the resut value of a run
241
- # @return [Boolean]
242
- def Circuits.control(circuit: , values: )
236
+ # @param [Hash] values the resut value of a run
237
+ # @return [Boolean]
238
+ def self.control(circuit:, values:)
243
239
  data = @@circuits_store.get key: circuit
244
- data[:status] = {:general => :closed, :failure_count => 0, :overtime_count => 0, :timeout_count => 0} unless data.include? :status
245
- data[:values] = Array::new unless data.include? :values
240
+ unless data.include? :status
241
+ data[:status] =
242
+ { general: :closed, failure_count: 0, overtime_count: 0, timeout_count: 0 }
243
+ end
244
+ data[:values] = [] unless data.include? :values
246
245
  level = [data[:max_failure_count].to_i, data[:max_timeout_count].to_i, data[:max_overtime_count].to_i].max
247
246
  data[:values].shift if data[:values].size > level
248
247
  data[:values].push values
249
248
  worst_status = []
250
- ['failure','overtime','timeout'].each do |control|
251
- if values[control.to_sym] == true then
249
+ %w[failure overtime timeout].each do |control|
250
+ if values[control.to_sym] == true
252
251
  data[:status]["#{control}_count".to_sym] += 1
253
252
  else
254
253
  data[:status]["#{control}_count".to_sym] = 0
255
254
  end
256
-
255
+
257
256
  case data[:status]["#{control}_count".to_sym]
258
257
  when 0
259
258
  worst_status.push :closed
@@ -264,16 +263,23 @@ module Sc4ry
264
263
  end
265
264
  end
266
265
  save = data[:status][:general]
267
- [:closed,:half_open,:open].each do |status|
266
+ %i[closed half_open open].each do |status|
268
267
  data[:status][:general] = status if worst_status.include? status
269
268
  end
270
- if save != data[:status][:general] then
271
- raise CircuitBreaked if data[:status][:general] == :open and data[:raise_on_opening]
272
- Sc4ry::Helpers.log level: :error, message: "Circuit #{circuit} : breacking ! " if data[:status][:general] == :open
273
- Sc4ry::Helpers.log level: :info, message: "Circuit #{circuit} : is now closed" if data[:status][:general] == :closed
274
- Sc4ry::Helpers.notify circuit: circuit, config: data
275
- end
269
+ if save != data[:status][:general]
270
+ raise CircuitBreaked if data[:status][:general] == :open && data[:raise_on_opening]
271
+
272
+ if data[:status][:general] == :open
273
+ Sc4ry::Helpers.log level: :error,
274
+ message: "Circuit #{circuit} : breacking ! "
275
+ end
276
+ if data[:status][:general] == :closed
277
+ Sc4ry::Helpers.log level: :info,
278
+ message: "Circuit #{circuit} : is now closed"
279
+ end
280
+ Sc4ry::Helpers.notify circuit: circuit, config: data
281
+ end
276
282
  @@circuits_store.put key: circuit, value: data
277
283
  end
278
284
  end
279
- end
285
+ end