sc4ry 0.1.8 → 0.2.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: 19791a7d72756fe96464fd43fd648010a71ff7491b96702da23c8828c19f58a2
4
- data.tar.gz: 6e1d7318a3de28fd0950213f9e8bf344819dc5858f66f5ce0ec5b1eb7275b99f
3
+ metadata.gz: f4cbfc8c2a7a821c3374916cdd69650a91f1eca5faa4dbbd93ac94e29dae5f89
4
+ data.tar.gz: dfa68d210342122e96e6f9fcd234fa73f6fefee667addac8371424b39c1b63d4
5
5
  SHA512:
6
- metadata.gz: 7f2c87ddb8ee4dc04aa1d6b2b9b9f214309fc56749dbb85a648f541ca1c27621dffdfcb9619348c3cd57874f5f9e9f0c24371fc9926150d32bb62edf3d5e4798
7
- data.tar.gz: b43b8a8a6611fa76c890b10ccc40ffbee0f035bf8af298891919dbb9b4bf3ece9fb1ef13fb5386f0807c11e188d6cf7e9448979a4dc3552a62d1043cf53c3a78
6
+ metadata.gz: 82590002c1ac457715776b0be304d77fa2903885cc4dc21ee45cea87ee070648661b48520453ab011cd287da49997990b4e607940a54954f5f82b5c884089715
7
+ data.tar.gz: 8b63d6b39cee270a1e1ab38ffcde491b746011126615bc4a5908b9f8790017f0c30c8899453ca1848ee4022f8528a0edd61587b583d58a8404e4eef139ecbb84
@@ -0,0 +1,27 @@
1
+ name: Ruby
2
+
3
+ on: [push,pull_request]
4
+
5
+ jobs:
6
+ container-job:
7
+ runs-on: ubuntu-latest
8
+ container: ruby:latest
9
+ services:
10
+ redis:
11
+ image: redis
12
+ pushgateway:
13
+ image: prom/pushgateway
14
+
15
+ steps:
16
+ - uses: actions/checkout@v2
17
+ - name: Run the default task
18
+ run: |
19
+ gem install bundler -v 2.2.3
20
+ bundle install
21
+ bundle exec rake
22
+ env:
23
+ # The hostname used to communicate with the Redis service container
24
+ REDIS_HOST: redis
25
+ REDIS_PORT: 6379
26
+ PROM_PG_PORT: 9091
27
+ PROM_PG_HOST: pushgateway
data/.gitignore CHANGED
@@ -6,6 +6,6 @@
6
6
  /pkg/
7
7
  /spec/reports/
8
8
  /tmp/
9
-
9
+ /yardoc/
10
10
  # rspec failure tracking
11
11
  .rspec_status
data/Gemfile CHANGED
@@ -6,4 +6,7 @@ gemspec
6
6
  gem "rake", "~> 12.0"
7
7
  gem "rspec", "~> 3.0"
8
8
  gem "prometheus-client", "~> 3.0"
9
- gem "rest-client", "~> 2.1"
9
+ gem "rest-client", "~> 2.1"
10
+ gem "redis", "~> 4.6"
11
+ gem "version", "~> 1.1"
12
+
data/README.md CHANGED
@@ -2,7 +2,25 @@
2
2
 
3
3
  Sc4ry provide the Circuit Breaker Design Pattern for your applications
4
4
 
5
- ![Sc4ry logo](assets/images/logo_sc4ry.png) _Simple CircuitBreacker 4 RubY_
5
+ [![Ruby](https://github.com/Ultragreen/Sc4ry/workflows/Ruby/badge.svg)](https://github.com/Ultragreen/sc4ry/actions?query=workflow%3ARuby+branch%3Amaster)
6
+ ![GitHub](https://img.shields.io/github/license/Ultragreen/sc4ry)
7
+
8
+ [![Documentation](https://img.shields.io/badge/docs-rubydoc.info-brightgreen)](https://rubydoc.info/gems/sc4ry)
9
+ ![GitHub issues](https://img.shields.io/github/issues/Ultragreen/sc4ry)
10
+ ![GitHub tag (latest by date)](https://img.shields.io/github/v/tag/Ultragreen/sc4ry)
11
+ ![GitHub top language](https://img.shields.io/github/languages/top/Ultragreen/sc4ry)
12
+ ![GitHub milestones](https://img.shields.io/github/milestones/open/Ultragreen/sc4ry)
13
+
14
+ ![Gem](https://img.shields.io/gem/dt/sc4ry)
15
+ [![Gem Version](https://badge.fury.io/rb/sc4ry.svg)](https://badge.fury.io/rb/sc4ry)
16
+ ![Twitter Follow](https://img.shields.io/twitter/follow/Ultragreen?style=social)
17
+ ![GitHub Org's stars](https://img.shields.io/github/stars/Ultragreen?style=social)
18
+ ![GitHub watchers](https://img.shields.io/github/watchers/Ultragreen/sc4ry?style=social)
19
+
20
+ <noscript><a href="https://liberapay.com/ruydiaz/donate"><img alt="Donate using Liberapay" src="https://liberapay.com/assets/widgets/donate.svg"></a></noscript>
21
+
22
+ ![Sc4ry logo](assets/images/logo_sc4ry.png)
23
+ _Simple CircuitBreacker 4 RubY_
6
24
 
7
25
  ## Installation
8
26
 
@@ -22,6 +40,9 @@ Or install it yourself as:
22
40
 
23
41
  ## Usage
24
42
 
43
+ ### Circuits States Worflow
44
+
45
+ ![Sc4ry workflow](assets/images/sc4ry_workflow.png)
25
46
  ### sample with Restclient
26
47
 
27
48
  ```ruby
@@ -109,8 +130,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
109
130
 
110
131
  ## Contributing
111
132
 
112
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/sc4ry. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/sc4ry/blob/master/CODE_OF_CONDUCT.md).
113
-
133
+ Bug reports and pull requests are welcome on GitHub at https://github.com/Ultragreen/sc4ry.
114
134
 
115
135
  ## License
116
136
 
data/Rakefile CHANGED
@@ -1,6 +1,37 @@
1
1
  require "bundler/gem_tasks"
2
2
  require "rspec/core/rake_task"
3
+ require 'yard'
4
+ require 'yard/rake/yardoc_task.rb'
5
+ require 'code_statistics'
6
+ require "roodi"
7
+ require "roodi_task"
8
+ require "version"
9
+ require 'rake/version_task'
10
+ Rake::VersionTask.new
11
+
12
+
13
+ RoodiTask.new() do | t |
14
+ t.patterns = %w(lib/**/*.rb)
15
+ t.config = "ultragreen_roodi_coding_convention.yml"
16
+ end
17
+
3
18
 
4
19
  RSpec::Core::RakeTask.new(:spec)
5
20
 
6
21
  task :default => :spec
22
+
23
+
24
+ YARD::Rake::YardocTask.new do |t|
25
+ t.files = [ 'lib/**/*.rb', '-', 'doc/**/*','spec/**/*_spec.rb']
26
+ t.options += ['-o', "yardoc"]
27
+ end
28
+ YARD::Config.load_plugin('yard-rspec')
29
+
30
+ namespace :yardoc do
31
+ task :clobber do
32
+ rm_r "yardoc" rescue nil
33
+ rm_r ".yardoc" rescue nil
34
+ rm_r "pkg" rescue nil
35
+ end
36
+ end
37
+ task :clobber => "yardoc:clobber"
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.2.0
Binary file
@@ -1,33 +1,60 @@
1
+ # Sc4ry module
2
+ # @note namespace
1
3
  module Sc4ry
4
+
5
+ # Sc4ry:Backends module
6
+ # @note namespace
2
7
  module Backends
3
8
 
9
+ # class of the memory backend
4
10
  class Memory
11
+
12
+ # Constructor
13
+ # @param [Hash] config Config map
14
+ # @return [Sc4ry::Backends::Memory] a in Memory backend
5
15
  def initialize(config=nil?)
6
16
  @data = Hash::new
7
17
  end
8
18
 
19
+ # return the list of find records in backend for a specific pattern
20
+ # @return [Array] list of record (for all hostname if hostname is specified)
9
21
  def list
10
22
  return @data.keys
11
23
  end
12
24
 
13
- def get(options)
14
- return @data[options[:key]]
25
+ # return value of queried record
26
+ # @param key [Symbol] the name of the record
27
+ # @return [String] content value of record
28
+ def get(key: )
29
+ return @data[key]
15
30
  end
16
31
 
17
- def put(options)
18
- @data[options[:key]] = options[:value]
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[key] = value
19
38
  end
20
39
 
21
- def del(options)
22
- @data.delete options[:key]
40
+ # delete a specific record
41
+ # @param params [Symbol] the name of the record
42
+ # @return [Boolean] status of the operation
43
+ def del(key: )
44
+ @data.delete key
23
45
  end
24
46
 
47
+ # flush all records in backend
48
+ # @return [Boolean] status of the operation
25
49
  def flush
26
50
  @data.clear
27
51
  end
28
52
 
29
- def exist?(options)
30
- return @data.include? options[:key]
53
+ # verifiy a specific record existence
54
+ # @param key [Symbol] the name of the record
55
+ # @return [Boolean] presence of the record
56
+ def exist?(key: )
57
+ return @data.include? key
31
58
  end
32
59
 
33
60
  end
@@ -16,46 +16,47 @@ module Sc4ry
16
16
  # return the list of find records in backend for a specific pattern
17
17
  # @return [Array] list of record (for all hostname if hostname is specified)
18
18
  def list
19
- return @store.keys('*')
19
+ return @be.keys('*').map(&:to_sym)
20
20
  end
21
21
 
22
22
 
23
23
  # return value of queried record
24
- # @param [Hash] options
25
- # @option options [Symbol] :key the name of the record
24
+ # @param key [Symbol] the name of the record
26
25
  # @return [String] content value of record
27
- def get(options)
28
- return @store.get(options[:key])
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
29
30
  end
30
31
 
31
32
  # defined and store value for specified key
32
- # @param [Hash] options
33
- # @option options [Symbol] :key the name of the record
34
- # @option options [Symbol] :value the content value of the record
33
+ # @param key [Symbol] :key the name of the record
34
+ # @param value [Symbol] :value the content value of the record
35
35
  # @return [String] content value of record
36
- def put(options)
37
- @store.set options[:key], options[:value]
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
38
40
  end
39
41
 
40
42
  # delete a specific record
41
- # @param [Hash] options
42
- # @option options [Symbol] :key the name of the record
43
+ # @param key [Symbol] the name of the record
43
44
  # @return [Boolean] status of the operation
44
- def del(options)
45
- @store.del options[:key]
45
+ def del(key: )
46
+ @be.del key
46
47
  end
47
48
 
48
49
  # flush all records in backend
50
+ # @return [Boolean] status of the operation
49
51
  def flush
50
- @store.flushdb
52
+ @be.flushdb
51
53
  end
52
54
 
53
- # verifiy a specific record existance
54
- # @param [Hash] options
55
- # @option options [Symbol] :key the name of the record
55
+ # verifiy a specific record existence
56
+ # @param key [Symbol] the name of the record
56
57
  # @return [Boolean] presence of the record
57
- def exist?(options)
58
- return ( not @store.get(options[:key]).nil?)
58
+ def exist?(key: )
59
+ return ( not @be.get(key).nil?)
59
60
  end
60
61
 
61
62
 
@@ -1,17 +1,56 @@
1
+ # Sc4ry Module
2
+ # @note namespace
1
3
  module Sc4ry
4
+
5
+ # Circuits and default configuration management class
2
6
  class Circuits
3
7
 
4
8
  include Sc4ry::Constants
5
9
  include Sc4ry::Exceptions
6
10
 
7
11
  @@circuits_store = Sc4ry::Store.instance
8
-
12
+ @@circuits_notifiers = Sc4ry::Notifiers
13
+ @@circuits_loggers = Sc4ry::Loggers
9
14
  @@config = DEFAULT_CONFIG
10
15
 
16
+ # @!group forwarders
17
+
18
+ # Class method how forward the Notifiers class factory/manager
19
+ # @return [Sc4ry::Notifiers]
20
+ def Circuits.notifiers
21
+ return @@circuits_notifiers
22
+ end
23
+
24
+ # Class method how forward a Store manager class singleton
25
+ # @return [Sc4ry::Store]
26
+ def Circuits.store
27
+ return @@circuits_store
28
+ end
29
+
30
+ # Class method how forward the Logger manager class factory/manager
31
+ # @return [Sc4ry::Store]
32
+ def Circuits.loggers
33
+ return @@circuits_loggers
34
+ end
35
+
36
+
37
+
38
+ # @!endgroup
39
+
40
+
41
+ # @!group Default Sc4ry configuration management
42
+
43
+ # Class method how return de default Sc4ry config
44
+ # @return [Hash]
11
45
  def Circuits.default_config
12
46
  return @@config
13
47
  end
14
48
 
49
+ # class method how merge a differential hash to default config
50
+ # @param [Hash] diff the differential hash config
51
+ # @example usage
52
+ # include Sc4ry
53
+ # Circuits.merge_default_config diff: {max_time: 20, notifiers: [:mattermost]}
15
54
  def Circuits.merge_default_config(diff:)
16
55
  validator = Sc4ry::Config::Validator::new(definition: diff, from: @@config)
17
56
  validator.validate!
@@ -19,6 +58,13 @@ module Sc4ry
19
58
 
20
59
  end
21
60
 
61
+ # class method for specifiying config by block
62
+ # @yield [Sc4ry::Config::ConfigMapper]
63
+ # @example usage
64
+ # include Sc4ry
65
+ # Circuits.configure do |spec|
66
+ # spec.max_failure_count = 3
67
+ # end
22
68
  def Circuits.configure(&bloc)
23
69
  mapper = Sc4ry::Config::ConfigMapper::new(definition: @@config.dup)
24
70
  yield(mapper)
@@ -28,11 +74,33 @@ module Sc4ry
28
74
  end
29
75
 
30
76
 
77
+ # old default config setter
78
+ # @deprecated use {.merge_default_config} instead
79
+ # @param [Hash] config
31
80
  def Circuits.default_config=(config)
32
81
  Sc4ry::Helpers.log level: :warn, message: "DEPRECATED: Circuits.default_config= is deprecated please use Circuits.merge_default_config add: {<config_hash>}"
33
82
  Circuits.merge_default_config(diff: config)
34
83
  end
35
84
 
85
+ # @!endgroup
86
+
87
+ # @!group Circuits management
88
+
89
+ # class method for registering a new circuit, cloud work with a block
90
+ # @yield [Sc4ry::Config::ConfigMapper]
91
+ # @param [Symbol] circuit a circuit name
92
+ # @param [Hash] config a config override on default config for the circuit
93
+ # @example usage
94
+ # include Sc4ry
95
+ # Circuits.register circuit: :mycircuit, config: {raise_on_opening: true, timeout: true}
96
+ # # or
97
+ # Circuits.register circuit: :mycircuit do |spec|
98
+ # spec.raise_on_opening = true
99
+ # spec.timeout = true
100
+ # end
101
+ # @return [Hash] the full config of the circuit after merge on default
102
+ # @raise [Sc4ryGenericError] if use config keyword with a block
103
+ # @raise [Sc4ryGenericError] if circuit already exist in current store.
36
104
  def Circuits.register(circuit:, config: {})
37
105
  if config.size > 0 and block_given? then
38
106
  raise Sc4ryGenericError, "config: keyword must not be defined when block is given"
@@ -46,51 +114,141 @@ module Sc4ry
46
114
  end
47
115
  validator.validate!
48
116
  Sc4ry::Helpers.log level: :debug, message: "Circuit #{circuit} : registered"
117
+ raise Sc4ryGenericError, "Circuit: #{circuit} already exist in store" if @@circuits_store.exist? key: circuit
49
118
  @@circuits_store.put key: circuit, value: validator.result
119
+ return validator.result
50
120
  end
51
121
 
122
+ # class method how list all circuits in current store
123
+ # @example usage
124
+ # include Sc4ry
125
+ # circuits = Circuits.list
126
+ # @return [Array] the list of [Symbol] circuits name
52
127
  def Circuits.list
53
128
  return @@circuits_store.list
54
129
  end
55
130
 
131
+ # class method how flush all circuits in current store
132
+ # @example usage
133
+ # include Sc4ry
134
+ # Circuits.flush
135
+ # @return [true,false]
136
+ def Circuits.flush
137
+ return @@circuits_store.flush
138
+ end
56
139
 
57
- def Circuits.get(options)
58
- @@circuits_store.get key: options[:circuit]
140
+ # class method for unregistering a circuit
141
+ # @param [Symbol] circuit a circuit name
142
+ # @example usage
143
+ # include Sc4ry
144
+ # Circuits.unregister circuit: :mycircuit
145
+ # @raise [Sc4ryGenericError] if circuit not found in current store.
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
59
155
  end
60
156
 
61
- def Circuits.run(options = {}, &block)
157
+
158
+ # class method for get a specific circuit by circuit name
159
+ # @param [Symbol] circuit a circuit name
160
+ # @example usage
161
+ # include Sc4ry
162
+ # Circuits.get circuit: :mycircuit
163
+ # @return [Hash] the circuit record in current store included values and status if the circuit have already run.
164
+ def Circuits.get(circuit:)
165
+ @@circuits_store.get key: circuit
166
+ end
167
+
168
+ # class method for update the config of a specific circuit by circuit name
169
+ # @param [Symbol] circuit a circuit name
170
+ # @param [Hash] config a config hash to merge on current config
171
+ # @example usage
172
+ # include Sc4ry
173
+ # Circuits.update_config circuit: :mycircuit, config: {}
174
+ # @note : <b>important</b> updating config will reset status and values !
175
+ # @return [Hash] new config for this circuit
176
+ def Circuits.update_config(circuit: , config: {forward_unknown_exceptions: false})
177
+ raise Sc4ryGenericError, "Circuit #{circuit} not found" unless Circuits.list.include? circuit
178
+ save = @@circuits_store.get key: circuit
179
+ save.delete_if {|key,val| [:status,:values].include? key}
180
+ Circuits.unregister(circuit: circuit)
181
+ save.merge! config
182
+ return Circuits.register circuit: circuit, config: save
183
+ end
184
+
185
+ # class method for get the status of a specific circuit by circuit name
186
+ # @param [Symbol] circuit a circuit name
187
+ # @example usage
188
+ # include Sc4ry
189
+ # Circuits.status circuit: :mycircuit
190
+ # @return [Symbol] status must in [:open,:half_open,:closed,:never_run]
191
+ def Circuits.status(circuit:)
192
+ data = @@circuits_store.get key: circuit
193
+ return (data.include? :status)? data[:status][:general] : :never_run
194
+ end
195
+
196
+
197
+ # class method for running circuit, need a block
198
+ # @yield [Proc]
199
+ # @param [Symbol] circuit a circuit name
200
+ # @example usage
201
+ # include Sc4ry
202
+ # Circuits.run circuit: :mycircuit do
203
+ # # [...] your code like a Restclient.get("URL")
204
+ # end
205
+ # # or
206
+ # Circuits.run do
207
+ # # [...] your code like a Restclient.get("URL")
208
+ # # running with the first define circuit (use only on a one circuit usage)
209
+ # end
210
+ # @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)
62
213
  circuits_list = Circuits.list
63
214
  raise Sc4ryGenericError, "No circuit block given" unless block_given?
64
215
  raise Sc4ryGenericError, "No circuits defined" if circuits_list.empty?
65
- circuit_name = (options[:circuit])? options[:circuit] : circuits_list.first
216
+ circuit_name = (circuit)? circuit : circuits_list.first
66
217
  raise Sc4ryGenericError, "Circuit #{circuit_name} not found" unless circuits_list.include? circuit_name
67
- circuit = Circuits.get circuit: circuit_name
218
+ circuit_to_run = Circuits.get circuit: circuit_name
68
219
  skip = false
69
- if circuit.include? :status then
70
- if circuit[:status][:general] == :open then
220
+ if circuit_to_run.include? :status then
221
+ if circuit_to_run[:status][:general] == :open then
71
222
  @now = Process.clock_gettime(Process::CLOCK_MONOTONIC)
72
- skip = true if ((@now - circuit[:values].last[:end_time]) < circuit[:check_delay])
223
+ skip = true if ((@now - circuit_to_run[:values].last[:end_time]) < circuit_to_run[:check_delay])
73
224
  end
74
225
  end
75
226
  unless skip
76
- controller = Sc4ry::RunController.new(circuit)
227
+ controller = Sc4ry::RunController.new(circuit_to_run)
77
228
  Circuits.control circuit: circuit_name, values: controller.run(block: block)
78
229
  end
79
- Sc4ry::Helpers.log level: :debug, message: "Circuit #{circuit_name} : status #{circuit[:status]}"
80
-
230
+ result = @@circuits_store.get key: circuit_name
231
+ Sc4ry::Helpers.log level: :debug, message: "Circuit #{circuit_name} : status #{result[:status]}"
232
+ return result
81
233
  end
82
234
 
235
+ # @!endgroup
236
+
83
237
  private
84
- def Circuits.control(options={})
85
- data = @@circuits_store.get key: options[:circuit]
238
+ # the private class method to control circuits running status
239
+ # @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: )
243
+ data = @@circuits_store.get key: circuit
86
244
  data[:status] = {:general => :closed, :failure_count => 0, :overtime_count => 0, :timeout_count => 0} unless data.include? :status
87
245
  data[:values] = Array::new unless data.include? :values
88
246
  level = [data[:max_failure_count].to_i, data[:max_timeout_count].to_i, data[:max_overtime_count].to_i].max
89
247
  data[:values].shift if data[:values].size > level
90
- data[:values].push options[:values]
248
+ data[:values].push values
91
249
  worst_status = []
92
250
  ['failure','overtime','timeout'].each do |control|
93
- if options[:values][control.to_sym] == true then
251
+ if values[control.to_sym] == true then
94
252
  data[:status]["#{control}_count".to_sym] += 1
95
253
  else
96
254
  data[:status]["#{control}_count".to_sym] = 0
@@ -111,11 +269,11 @@ module Sc4ry
111
269
  end
112
270
  if save != data[:status][:general] then
113
271
  raise CircuitBreaked if data[:status][:general] == :open and data[:raise_on_opening]
114
- Sc4ry::Helpers.log level: :error, message: "Circuit #{options[:circuit]} : breacking ! " if data[:status][:general] == :open
115
- Sc4ry::Helpers.log level: :info, message: "Circuit #{options[:circuit]} : is now closed" if data[:status][:general] == :closed
116
- Sc4ry::Helpers.notify circuit: options[:circuit], config: data
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
117
275
  end
118
- @@circuits_store.put key: options[:circuit], value: data
276
+ @@circuits_store.put key: circuit, value: data
119
277
  end
120
278
  end
121
279
  end
data/lib/sc4ry/config.rb CHANGED
@@ -1,32 +1,49 @@
1
+ # Sc4ry module
2
+ # @note namespace
1
3
  module Sc4ry
4
+ # Sc4ry::Config module
5
+ # @note namespace
2
6
  module Config
7
+ # Configuration validator for Sc4ry default and circuits configuration
8
+ # @private
3
9
  class Validator
4
- attr_reader :definition
5
- attr_reader :default
10
+
11
+ # accessor on Circuit definition given for validation
12
+ attr_reader :input
13
+ # accessor on circuit initial definition from default config or given in construction by from keyword
14
+ # @note altered by reference to final result mapping with {#validate!}
15
+ attr_reader :config
6
16
 
7
17
  def result
8
- @default
18
+ @config
9
19
  end
10
20
 
11
21
  include Sc4ry::Constants
12
22
  include Sc4ry::Exceptions
13
-
23
+ # Validator constructor
24
+ # @param [Hash] definition the config hash to merge and validate
25
+ # @param [Hash] from config hash merged on origin (default : the Sc4ry base config from Constants )
26
+ # @return [Validator] a new instance of Validator
14
27
  def initialize(definition: , from: DEFAULT_CONFIG)
15
- @default = from
16
- @definition = definition
28
+ @config = from
29
+ @input = definition
17
30
  end
18
31
 
32
+ # Validation method, alter by reference the config attribut
33
+ # @raise ConfigError if un unknown key is given in definition to merge.
19
34
  def validate!
20
- unknown_keys = @definition.keys.difference @default.keys
35
+ unknown_keys = @input.keys.difference @config.keys
21
36
  raise ConfigError::new("Unknown keys in config set : #{unknown_keys.to_s}") unless unknown_keys.empty?
22
37
  validate_formats
23
- @default.merge! @definition
38
+ @config.merge! @input
24
39
  format_exceptions
25
40
  end
26
41
 
27
42
  private
43
+ # Validation private sub method
44
+ # @raise ConfigError if proposed values haven't the good format and deeply in array
28
45
  def validate_formats
29
- definition.each do |spec,value|
46
+ @input.each do |spec,value|
30
47
  raise ConfigError::new("#{spec} value #{DEFAULT_CONFIG_FORMATS[spec][:desc]}") unless DEFAULT_CONFIG_FORMATS[spec][:proc].call(value)
31
48
  if DEFAULT_CONFIG_FORMATS[spec].include? :list then
32
49
  value.each do |item|
@@ -36,17 +53,26 @@ module Sc4ry
36
53
  end
37
54
  end
38
55
 
56
+ # adapter for exception key in config String to Constant Class Name if need
57
+ # @note by reference
39
58
  def format_exceptions
40
- @default[:exceptions].map! {|item| item = (item.class == String)? Object.const_get(item) : item }
59
+ @config[:exceptions].map! {|item| item = (item.class == String)? Object.const_get(item) : item }
41
60
  end
42
61
 
43
62
  end
44
63
 
64
+ # Config Data mapper for block yielding methods for configuration
65
+ # @note work for/with {Sc4ry::Circuits.configure} and {Sc4ry::Circuits.register} when block given
45
66
  class ConfigMapper
46
67
 
47
68
  include Sc4ry::Constants
69
+
70
+ # config from given definition passed in constructor
48
71
  attr_reader :config
49
72
 
73
+ # the mapping constructor from a given definition or the default From Sc4ry config (Constant)
74
+ # @param [Hash] definition a config hash
75
+ # @note creating dynamically accessors on config record given in definition
50
76
  def initialize(definition: DEFAULT_CONFIG)
51
77
  @config = definition
52
78
  @config.each do |key,value|
@@ -1,7 +1,14 @@
1
+ # Sc4ry module
2
+ # @note namespace
1
3
  module Sc4ry
4
+ # Sc4ry::Constants module
5
+ # @note namespace
2
6
  module Constants
3
7
 
8
+ # notifiers available in Sc4ry natively
4
9
  CURRENT_NOTIFIERS = [:prometheus, :mattermost]
10
+
11
+ # the Sc4ry default config entries and values
5
12
  DEFAULT_CONFIG = {
6
13
  :max_failure_count => 5,
7
14
  :timeout_value => 20,
@@ -16,6 +23,7 @@ module Sc4ry
16
23
  :exceptions => [StandardError, RuntimeError]
17
24
  }
18
25
 
26
+ # Default config supported entries with format and Proc checker for {Sc4ry::Config::Validator}
19
27
  DEFAULT_CONFIG_FORMATS = {
20
28
  :max_failure_count => {:proc => Proc::new {|item| item.class == Integer}, :desc => "must be an Integer"},
21
29
  :timeout_value => {:proc => Proc::new {|item| item.class == Integer}, :desc => "must be an Integer"},