sc4ry 0.1.6 → 0.2.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.
@@ -1,29 +1,56 @@
1
1
  Dir[File.dirname(__FILE__) + '/*.rb'].sort.each { |file| require file unless File.basename(file) == 'init.rb' }
2
2
 
3
+ # Sc4ry module
4
+ # @note namespace
3
5
  module Sc4ry
4
- module Notifiers
5
- @@notifiers_list = {:prometheus => {:class => Sc4ry::Notifiers::Prometheus, :config => {:url => 'http://localhost:9091'}},
6
- :mattermost => {:class => Sc4ry::Notifiers::Mattermost, :config => {:url => 'http://localhost:9999', :token => "<CHANGE_ME>"}}
7
- }
8
6
 
7
+ # Sc4ry::Notifiers module
8
+ # @note namespace
9
+ module Notifiers
10
+
11
+ # default notifiers specifications
12
+ DEFAULT_NOTIFIERS = {:prometheus => {:class => Sc4ry::Notifiers::Prometheus, :config => {:url => 'http://localhost:9091'}},
13
+ :mattermost => {:class => Sc4ry::Notifiers::Mattermost, :config => {:url => 'http://localhost:9999', :token => "<CHANGE_ME>"}}
14
+ }
15
+ @@notifiers_list = DEFAULT_NOTIFIERS.dup
16
+
17
+ # class method how display a specific notifier config
18
+ # @param notifier [Symbol] a notifier name
19
+ # @return [Hash] the config
20
+ def Notifiers.display_config(notifier: )
21
+ raise Sc4ry::Exceptions::Sc4ryNotifierError, "Notifier #{notifier} not found" unless @@notifiers_list.include? notifier
22
+ return @@notifiers_list[notifier][:config]
23
+ end
24
+
25
+ # class method how return the list of known notifiers
26
+ # @return [Array] a list of [Symbol] notifiers name
9
27
  def Notifiers.list
10
28
  return @@notifiers_list.keys
11
29
  end
12
30
 
13
- def Notifiers.get(options ={})
14
- return @@notifiers_list[options[:name]]
31
+ # class method how return a specific notifier by name
32
+ # @param name [Symbol] a notifier name
33
+ # @return [Hash] the notifier structure
34
+ def Notifiers.get(name: )
35
+ return @@notifiers_list[name]
15
36
  end
16
37
 
17
- def Notifiers.register(options)
18
- raise ":name is mandatory" unless options[:name]
19
- raise ":definition is mandatory" unless options[:definition]
20
- @@notifiers_list[options[:name]] = options[:definition]
38
+ # class method how register a specific notifier
39
+ # @param name [Symbol] a notifier name
40
+ # @param definition [Hash] a notifier definition
41
+ # @return [Hash] the notifier structure
42
+ def Notifiers.register(name: , definition: )
43
+ @@notifiers_list[name] = definition
21
44
  end
22
45
 
23
- def Notifiers.config(options)
24
- raise ":name is mandatory" unless options[:name]
25
- raise ":config is mandatory" unless options[:config]
26
- @@notifiers_list[options[:name]][:config] = options[:config]
46
+
47
+ # class method how configure a specific notifier
48
+ # @param name [Symbol] a notifier name
49
+ # @param config [Hash] a notifier config
50
+ # @return [Hash] the notifier structure
51
+ def Notifiers.config(name:, config: )
52
+ @@notifiers_list[name][:config] = config
53
+ return config
27
54
  end
28
55
  end
29
56
  end
@@ -1,33 +1,41 @@
1
+ # Sc4ry module
2
+ # @note namespace
1
3
  module Sc4ry
4
+ # Sc4ry::Notifiers module
5
+ # @note namespace
2
6
  module Notifiers
3
7
 
8
+ # Mattermost Notifier class
4
9
  class Mattermost
5
10
 
6
11
  # send metrics to Prometheus PushGateway
7
12
  # @return [Bool]
8
13
  def Mattermost.notify(options = {})
9
- config = Sc4ry::Notifiers.get({name: :mattermost})[:config]
14
+ config = Sc4ry::Notifiers.get(name: :mattermost)[:config]
10
15
  status = options[:config][:status][:general]
11
16
  circuit = options[:circuit]
12
17
  status_map = {:open => 0, :half_open => 1, :closed => 2}
13
-
14
- uri = URI.parse("#{config[:url]}/hooks/#{config[:token]}")
15
- message = "notifying for circuit #{circuit.to_s}, state : #{status.to_s}."
16
- if Sc4ry::Helpers::verify_service url: config[:url] then
17
- request = ::Net::HTTP::Post.new(uri)
18
- request.content_type = "application/json"
19
- req_options = {
20
- use_ssl: uri.scheme == "https",
21
- }
22
- payload = { "text" => "message : #{message } from #{Socket.gethostname}", "username" => "Sc4ry" }
23
- Sc4ry::Helpers.log level: :debug, message: "Mattermost Notifier : #{message}"
24
- request.body = ::JSON.dump(payload)
25
- response = ::Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
26
- http.request(request)
18
+ begin
19
+ uri = URI.parse("#{config[:url]}/hooks/#{config[:token]}")
20
+ message = "notifying for circuit #{circuit.to_s}, state : #{status.to_s}."
21
+ if Sc4ry::Helpers::verify_service url: config[:url] then
22
+ request = ::Net::HTTP::Post.new(uri)
23
+ request.content_type = "application/json"
24
+ req_options = {
25
+ use_ssl: uri.scheme == "https",
26
+ }
27
+ payload = { "text" => "message : #{message } from #{Socket.gethostname}", "username" => "Sc4ry" }
28
+ Sc4ry::Helpers.log level: :debug, message: "Mattermost Notifying : #{message}"
29
+ request.body = ::JSON.dump(payload)
30
+ response = ::Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
31
+ http.request(request)
32
+ end
33
+
34
+ else
35
+ Sc4ry::Helpers.log level: :warn, message: "Mattermost Notifier : can't notify Mattermost not reachable."
27
36
  end
28
-
29
- else
30
- Sc4ry::Helpers.log level: :warn, message: "Mattermost Notifier : can't notify Mattermost not reachable."
37
+ rescue URI::InvalidURIError
38
+ Sc4ry::Helpers.log level: :warn, message: "Mattermost Notifier : URL malformed"
31
39
  end
32
40
  end
33
41
  end
@@ -1,7 +1,13 @@
1
+ # Sc4ry module
2
+ # @note namespace
1
3
  module Sc4ry
4
+
5
+ # Sc4ry::Notifiers module
6
+ # @note namespace
2
7
  module Notifiers
3
8
 
4
9
 
10
+ # Prometheus notifier class
5
11
  class Prometheus
6
12
 
7
13
  @@registry = ::Prometheus::Client::Registry::new
@@ -14,7 +20,7 @@ module Sc4ry
14
20
  # send metrics to Prometheus PushGateway
15
21
  # @return [Bool]
16
22
  def Prometheus.notify(options = {})
17
- @config = Sc4ry::Notifiers.get({name: :prometheus})[:config]
23
+ @config = Sc4ry::Notifiers.get(name: :prometheus)[:config]
18
24
  status = options[:config][:status][:general]
19
25
  circuit = options[:circuit]
20
26
  status_map = {:open => 0, :half_open => 1, :closed => 2}
@@ -1,9 +1,16 @@
1
1
 
2
+ # Sc4ry module
3
+ # @note namespace
2
4
  module Sc4ry
5
+
6
+ # class Facility to run and update values/status for a circuit Proc
3
7
  class RunController
4
8
 
9
+ # return the execution time of the proc
5
10
  attr_reader :execution_time
6
11
 
12
+ # constructor
13
+ # @param [Hash] circuit the data of the circuit
7
14
  def initialize(circuit = {})
8
15
  @circuit = circuit
9
16
  @execution_time = 0
@@ -12,38 +19,47 @@ module Sc4ry
12
19
  @overtime = false
13
20
  end
14
21
 
22
+ # return if the Proc failed on a covered exception by this circuit
23
+ # @return [Boolean]
15
24
  def failed?
16
25
  return @failure
17
26
  end
18
-
27
+
28
+ # return if the Proc overtime the specified time of the circuit
29
+ # @return [Boolean]
19
30
  def overtimed?
20
31
  return @overtime
21
32
  end
22
33
 
34
+ # return if the Proc timeout the timeout defined value of the circuit, if timeout is active
35
+ # @return [Boolean]
23
36
  def timeout?
24
37
  return @timeout
25
38
  end
26
39
 
27
-
28
- def run(options = {})
40
+ # run and update values for the bloc given by keyword
41
+ # @param [Proc] block a block to run and calculate
42
+ # @return [Hash] a result Hash
43
+ def run(block: )
29
44
  start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
30
45
  begin
31
46
  if @circuit[:timeout] == true
32
47
  Timeout::timeout(@circuit[:timeout_value]) do
33
- options[:block].call
48
+ block.call
34
49
  end
35
50
  @timeout = false
36
51
  else
37
- options[:block].call
52
+ block.call
38
53
  end
39
54
  rescue Exception => e
40
- @last_exception = e.class
55
+ @last_exception = e.class.to_s
41
56
  if e.class == Timeout::Error then
42
57
  @timeout = true
43
58
  elsif @circuit[:exceptions].include? e.class
44
59
  @failure = true
45
60
  else
46
61
  if @circuit[:forward_unknown_exceptions] then
62
+
47
63
  raise e.class, "Sc4ry forward: #{e.message}"
48
64
  else
49
65
  Sc4ry::Helpers.log level: :debug, message: "skipped : #{@last_exception}"
data/lib/sc4ry/store.rb CHANGED
@@ -1,4 +1,10 @@
1
+ # Sc4ry module
2
+ # @note namespace
1
3
  module Sc4ry
4
+
5
+ # Sc4ry::Store class
6
+ # Store Class Provider/manager singleton Forwarder on {Sc4ry::Backends::Memory} or {Sc4ry::Backends::Redis}
7
+ # @note must be accessed by {Sc4ry::Circuits.store}
2
8
  class Store
3
9
 
4
10
  @@current = :memory
@@ -6,35 +12,92 @@ module Sc4ry
6
12
  extend Forwardable
7
13
  include Singleton
8
14
 
9
- @@backends = {:memory => {:class => Sc4ry::Backends::Memory},
15
+ @@backends = {:memory => {:class => Sc4ry::Backends::Memory, config: {}},
10
16
  :redis => {:class => Sc4ry::Backends::Redis, :config => {:host => 'localhost', :port => 6379, :db => 10 }}}
11
17
 
18
+ # accessor on current backend (default :memory)
12
19
  attr_reader :be
20
+
13
21
  def_delegators :@be, :put, :get, :flush, :exist?, :del, :list
14
22
 
23
+ # constructor pointing on :memory backend
15
24
  def initialize
16
25
  change_backend name: @@current
17
26
  end
18
27
 
28
+ # return the current backend
29
+ # @return [Object] in {Sc4ry::Backends::Memory} or {Sc4ry::Backends::Redis}
30
+ # @example usage
31
+ # include Sc4ry
32
+ # puts Circuits.store.current
19
33
  def current
20
34
  return @@current
21
35
  end
22
36
 
23
- def change_backend(options)
24
- @@current = options[:name]
37
+ # return the config of a specific backend
38
+ # @param [Symbol] backend the name the backend
39
+ # @return [Hash] the config of the backend
40
+ # @raise Sc4ry::Exceptions::Sc4ryBackendError if backend is not found
41
+ # @example usage
42
+ # include Sc4ry
43
+ # puts Circuits.store.get_config backend: :redis
44
+ def get_config(backend: )
45
+ raise Sc4ry::Exceptions::Sc4ryBackendError, "backend #{backend} not found" unless @@backends.include? backend
46
+ return @@backends[backend][:config]
47
+ end
48
+
49
+ # list backend available
50
+ # @return [Array] of Symbol the list of backend name
51
+ # @example usage
52
+ # include Sc4ry
53
+ # puts Circuits.store.list_backend
54
+ def list_backend
55
+ return @@backends.keys
56
+ end
57
+
58
+ # change the current backend
59
+ # @note if changing form :memory to :redis => all values and result are lost and circuits will be lost
60
+ # @note if changing to :redis, get all the define circuits with values and status (ideal) for distributed worker/instance/runner/services
61
+ # @param [Symbol] name the name of the target backend
62
+ # @return [Symbol] the name of the new current backend
63
+ # @raise Sc4ry::Exceptions::Sc4ryBackendError if backend is not found
64
+ def change_backend(name: )
65
+ raise Sc4ry::Exceptions::Sc4ryBackendError, "backend #{name} not found" unless @@backends.include? name
66
+ @@current = name
25
67
  @be = @@backends[@@current][:class]::new(@@backends[@@current][:config])
68
+ return name
26
69
  end
27
70
 
28
- def register_backend(options)
29
- raise ":name is mandatory" unless options[:name]
30
- raise ":definition is mandatory" unless options[:definition]
31
- @@backends[options[:name]] = options[:definition]
71
+ # register a new backend
72
+ # @param [Symbol] name the name of the backend
73
+ # @param [Hash] config the config for this backend
74
+ # @param [Class] backend_class the class name of the new backend
75
+ # @raise Sc4ry::Exceptions::Sc4ryBackendError if backend already exist
76
+ # @return [Symbol] the name of the backend
77
+ def register_backend(name:, config: {}, backend_class:)
78
+ raise Sc4ry::Exceptions::Sc4ryBackendError , "backend #{name} already exist" if @@backends.include? name
79
+ @@backends[name] = {config: config, class: backend_class}
80
+ return name
32
81
  end
33
82
 
34
- def config_backend(options)
35
- raise ":name is mandatory" unless options[:name]
36
- raise ":config is mandatory" unless options[:config]
37
- @@backends[options[:name]][:config] = options[:config]
83
+ # delete the specified backend reference
84
+ # @param [Symbol] name the name of the target backend
85
+ # @raise Sc4ry::Exceptions::Sc4ryBackendError if backend is not found, or name == :memory or :redis
86
+ # @return [Boolean]
87
+ def delete_backend(name: )
88
+ raise Sc4ry::Exceptions::Sc4ryBackendError , "Delete forbidden for backend in [:redis,:memory]" if [:memory,:redis].include? name
89
+ raise Sc4ry::Exceptions::Sc4ryBackendError , "backend #{name} not found" unless @@backends.include? name
90
+ return @@backends.delete(name)
91
+ end
92
+
93
+ # change the specified backend config
94
+ # @param [Symbol] name the name of the target backend
95
+ # @param [Hash] config the config of the specified backend
96
+ # @raise Sc4ry::Exceptions::Sc4ryBackendError if backend is not found, or name == :memory
97
+ def config_backend(name:, config:)
98
+ raise Sc4ry::Exceptions::Sc4ryBackendError, "backend #{name} not found" unless @@backends.include? name
99
+ raise Sc4ry::Exceptions::Sc4ryBackendError, "backend :memory not need config" if name == :memory
100
+ @@backends[name][:config] = config
38
101
  end
39
102
 
40
103
 
data/lib/sc4ry/version.rb CHANGED
@@ -1,3 +1,9 @@
1
+ require 'version'
2
+
3
+ # Sc4ry module
4
+ # @note namespace
1
5
  module Sc4ry
2
- VERSION = "0.1.6"
6
+
7
+ # the version of Sc4ry
8
+ VERSION = Version.current
3
9
  end
data/sc4ry.gemspec CHANGED
@@ -1,8 +1,7 @@
1
- require_relative 'lib/sc4ry/version'
2
1
 
3
2
  Gem::Specification.new do |spec|
4
3
  spec.name = "sc4ry"
5
- spec.version = Sc4ry::VERSION
4
+ spec.version = `cat VERSION`.chomp
6
5
  spec.authors = ["Romain GEORGES"]
7
6
  spec.email = ["romain.georges@orange.com"]
8
7
 
@@ -22,6 +21,11 @@ Gem::Specification.new do |spec|
22
21
 
23
22
  spec.add_dependency "prometheus-client", "~> 3.0"
24
23
  spec.add_dependency "rest-client", "~> 2.1"
24
+ spec.add_dependency "redis", "~> 4.6"
25
25
 
26
-
26
+ spec.add_development_dependency "yard", "~> 0.9.27"
27
+ spec.add_development_dependency 'code_statistics', '~> 0.2.13'
28
+ spec.add_development_dependency "yard-rspec", "~> 0.1"
29
+ spec.add_development_dependency "roodi", "~> 5.0"
30
+ spec.add_dependency "version", "~> 1.1"
27
31
  end
@@ -0,0 +1,25 @@
1
+ AssignmentInConditionalCheck:
2
+ CaseMissingElseCheck:
3
+ ClassLineCountCheck:
4
+ line_count: 300 # including comments yard
5
+ ClassNameCheck:
6
+ pattern: !ruby/regexp /^[A-Z][a-zA-Z0-9]*$/
7
+ #ClassVariableCheck:
8
+ CyclomaticComplexityBlockCheck:
9
+ complexity: 5
10
+ CyclomaticComplexityMethodCheck:
11
+ complexity: 10
12
+ EmptyRescueBodyCheck:
13
+ ForLoopCheck:
14
+ MethodLineCountCheck:
15
+ line_count: 30
16
+ MethodNameCheck:
17
+ pattern: !ruby/regexp /^[_a-z<>=\[|+-\/\*`]+[_a-z0-9_<>=~@\[\]]*[=!\?]?$/
18
+ # MissingForeignKeyIndexCheck:
19
+ ModuleLineCountCheck:
20
+ line_count: 300
21
+ ModuleNameCheck:
22
+ pattern: !ruby/regexp /^[A-Z][a-zA-Z0-9]*$/
23
+ ParameterNumberCheck:
24
+ parameter_count: 5
25
+
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sc4ry
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Romain GEORGES
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-03-08 00:00:00.000000000 Z
11
+ date: 2022-03-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: prometheus-client
@@ -38,6 +38,90 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '2.1'
41
+ - !ruby/object:Gem::Dependency
42
+ name: redis
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '4.6'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '4.6'
55
+ - !ruby/object:Gem::Dependency
56
+ name: yard
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 0.9.27
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.9.27
69
+ - !ruby/object:Gem::Dependency
70
+ name: code_statistics
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 0.2.13
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 0.2.13
83
+ - !ruby/object:Gem::Dependency
84
+ name: yard-rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0.1'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0.1'
97
+ - !ruby/object:Gem::Dependency
98
+ name: roodi
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '5.0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '5.0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: version
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '1.1'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '1.1'
41
125
  description: Sc4ry provide the design pattern Circuit breaker for your application.
42
126
  email:
43
127
  - romain.georges@orange.com
@@ -45,14 +129,16 @@ executables: []
45
129
  extensions: []
46
130
  extra_rdoc_files: []
47
131
  files:
132
+ - ".github/workflows/main.yml"
48
133
  - ".gitignore"
49
134
  - ".rspec"
50
135
  - Gemfile
51
136
  - LICENSE.txt
52
137
  - README.md
53
138
  - Rakefile
139
+ - VERSION
54
140
  - assets/images/logo_sc4ry.png
55
- - assets/logo_sc4ry.png
141
+ - assets/images/sc4ry_workflow.png
56
142
  - bin/console
57
143
  - bin/setup
58
144
  - lib/sc4ry.rb
@@ -60,6 +146,8 @@ files:
60
146
  - lib/sc4ry/backends/memory.rb
61
147
  - lib/sc4ry/backends/redis.rb
62
148
  - lib/sc4ry/circuits.rb
149
+ - lib/sc4ry/config.rb
150
+ - lib/sc4ry/constants.rb
63
151
  - lib/sc4ry/dependencies.rb
64
152
  - lib/sc4ry/exceptions.rb
65
153
  - lib/sc4ry/exporters/init.rb
@@ -72,11 +160,12 @@ files:
72
160
  - lib/sc4ry/store.rb
73
161
  - lib/sc4ry/version.rb
74
162
  - sc4ry.gemspec
163
+ - ultragreen_roodi_coding_convention.yml
75
164
  homepage: https://github.com/Ultragreen/sc4ry
76
165
  licenses:
77
166
  - MIT
78
167
  metadata: {}
79
- post_install_message:
168
+ post_install_message:
80
169
  rdoc_options: []
81
170
  require_paths:
82
171
  - lib
@@ -91,8 +180,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
91
180
  - !ruby/object:Gem::Version
92
181
  version: '0'
93
182
  requirements: []
94
- rubygems_version: 3.1.2
95
- signing_key:
183
+ rubygems_version: 3.2.3
184
+ signing_key:
96
185
  specification_version: 4
97
186
  summary: Sc4Ry is Simple Circuitbreaker 4 RubY
98
187
  test_files: []
Binary file