sc4ry 0.2.0 → 0.2.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,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