circuit_switch 0.2.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +58 -1
- data/README.md +50 -22
- data/circuit_switch.gemspec +1 -0
- data/lib/circuit_switch/builder.rb +66 -0
- data/lib/circuit_switch/configuration.rb +4 -0
- data/lib/circuit_switch/core.rb +41 -30
- data/lib/circuit_switch/notification.rb +1 -1
- data/lib/circuit_switch/orm/active_record/circuit_switch.rb +12 -3
- data/lib/circuit_switch/stacktrace_modifier.rb +1 -1
- data/lib/circuit_switch/tasks/circuit_switch.rake +15 -15
- data/lib/circuit_switch/version.rb +1 -1
- data/lib/circuit_switch/workers/due_date_notifier.rb +1 -1
- data/lib/circuit_switch/workers/reporter.rb +30 -13
- data/lib/circuit_switch/workers/run_count_updater.rb +23 -10
- data/lib/circuit_switch.rb +29 -36
- data/lib/generators/circuit_switch/migration_generator.rb +11 -1
- data/lib/generators/circuit_switch/templates/add_key.rb.erb +13 -0
- data/lib/generators/circuit_switch/templates/initializer.rb +7 -3
- data/lib/generators/circuit_switch/templates/make_key_unique.rb.erb +11 -0
- data/lib/generators/circuit_switch/templates/migration.rb.erb +3 -0
- metadata +19 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f1e87399b178858a0b41fce787342117deab9d4a1a29c7d9262d742be2633641
|
4
|
+
data.tar.gz: fdf0d9ec8723b02fea239de819f60e98b24de9904d034a40f549bcf90d895f26
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 075c7f6dfeef30c3e0faecadf30969dfa6cd1f8fd2b5e4e6f5934f0e15913ec98f4f6b8a3cf9c414a17e7b920d17ee22a01abcea18c9cf8af4bfc510562c8aba
|
7
|
+
data.tar.gz: 6df8910491782a75b873952c26e0ac5ebdb27aadcf93727fc044e1b5dd0eeb6bfcfceac04c30417b8f86b6ac1d0e6515b342dd8d0616fc0dc9f78f680816a232
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,60 @@
|
|
1
|
+
## 0.4.0
|
2
|
+
|
3
|
+
### Breaking Changes
|
4
|
+
|
5
|
+
* Be able to choice to notify `CircuitSwitch::CalledNotification` or `String`.
|
6
|
+
Improve `config/initializers/circuit_switch.rb` like following.
|
7
|
+
|
8
|
+
```diff
|
9
|
+
CircuitSwitch.configure do |config|
|
10
|
+
- config.reporter = ->(message) { Bugsnag.notify(message) }
|
11
|
+
+ config.reporter = ->(message, error) { Bugsnag.notify(error) }
|
12
|
+
```
|
13
|
+
|
14
|
+
## 0.3.0
|
15
|
+
|
16
|
+
### Breaking Changes
|
17
|
+
|
18
|
+
* Modify `key` to unique by default.
|
19
|
+
To migrate, run next.
|
20
|
+
|
21
|
+
```
|
22
|
+
rails generate circuit_switch:migration circuit_switch make_key_unique
|
23
|
+
rails db:migrate
|
24
|
+
```
|
25
|
+
|
26
|
+
### Changes
|
27
|
+
|
28
|
+
* Fix to save switch when block for `CircuitSwitch.run` raises error.
|
29
|
+
|
30
|
+
## 0.2.2
|
31
|
+
|
32
|
+
### New features
|
33
|
+
|
34
|
+
* Add `key_column_name` to configuration for aliasing `circuit_switches.key`.
|
35
|
+
|
36
|
+
### Changes
|
37
|
+
|
38
|
+
* Declare dependent on ActiveSupport instead of implicitly dependent.
|
39
|
+
|
40
|
+
## 0.2.1
|
41
|
+
|
42
|
+
### New features
|
43
|
+
|
44
|
+
* Add `initially_closed` option to `run` and `open?`.
|
45
|
+
* Add `key` argument for easy handling for human more than caller.
|
46
|
+
To migrate, run next.
|
47
|
+
|
48
|
+
```
|
49
|
+
rails generate circuit_switch:migration circuit_switch add_key
|
50
|
+
rails db:migrate
|
51
|
+
```
|
52
|
+
|
53
|
+
### Changes
|
54
|
+
|
55
|
+
* Modify log level from warn to info when default value for `close_if_reach_limit` is used.
|
56
|
+
* Suppress warning that ivar is not initialized.
|
57
|
+
|
1
58
|
## 0.2.0
|
2
59
|
|
3
60
|
### Breaking Changes
|
@@ -6,7 +63,7 @@
|
|
6
63
|
|
7
64
|
## 0.1.2
|
8
65
|
|
9
|
-
* Modify `CircuitSwitch.open?`
|
66
|
+
* Modify `CircuitSwitch.open?` receives same arguments as `CircuitSwitch.run`
|
10
67
|
|
11
68
|
## 0.1.1
|
12
69
|
|
data/README.md
CHANGED
@@ -37,7 +37,7 @@ rails generate circuit_switch:install
|
|
37
37
|
```
|
38
38
|
|
39
39
|
Generate a migration for ActiveRecord.
|
40
|
-
This table saves circuit caller, called count, limit count and so on.
|
40
|
+
This table saves named key, circuit caller, called count, limit count and so on.
|
41
41
|
|
42
42
|
```
|
43
43
|
rails generate circuit_switch:migration circuit_switch
|
@@ -56,21 +56,30 @@ CircuitSwitch.run do
|
|
56
56
|
end
|
57
57
|
```
|
58
58
|
|
59
|
-
`run` calls received proc
|
60
|
-
To switch circuit opening and closing,
|
61
|
-
You can
|
62
|
-
`run` receives optional arguments.
|
59
|
+
`run` basically calls the received proc. But when a condition is met, it closes the circuit and does not evaluate the proc.
|
60
|
+
To switch circuit opening and closing, a set of options can be set. Without options, the circuit is always open.
|
61
|
+
You can set `close_if_reach_limit: true` so that the circuit is only open for 10 invocations. The constant 10 comes from the table definition we have arbitrarily chosen. In case you need a larger number, specify it in the `limit_count` option in combination with `close_if_reach_limit: true`, or alter default constraint on `circuit_switches.run_limit_count`.
|
63
62
|
|
64
|
-
- `
|
65
|
-
- `
|
66
|
-
- `
|
67
|
-
- `
|
68
|
-
|
63
|
+
- `key`: [String] The identifier to find record by. If `key` has not been passed, `circuit_switches.caller` is chosen as an alternative.
|
64
|
+
- `if`: [Boolean, Proc] Calls proc when the value of `if` is evaluated truthy (default: true)
|
65
|
+
- `close_if`: [Boolean, Proc] Calls proc when the value of `close_if` is evaluated falsy (default: false)
|
66
|
+
- `close_if_reach_limit`: [Boolean] Stops calling proc when `circuit_switches.run_count` has reached `circuit_switches.run_limit_count` (default: false)
|
67
|
+
- `limit_count`: [Integer] Mutates `circuit_switches.run_limit_count` whose value defined in schema is 10 by default. (default: nil)
|
68
|
+
Can't be set to 0 when `close_if_reach_limit` is true. This option is only relevant when `close_if_reach_limit` is set to true.
|
69
|
+
- `initially_closed`: [Boolean] Creates switch with terminated mode (default: false)
|
69
70
|
|
70
|
-
To close the circuit at specific date
|
71
|
+
To close the circuit at a specific date, code goes like:
|
71
72
|
|
72
73
|
```ruby
|
73
|
-
CircuitSwitch.run(close_if: -> { Date.today >= some_day }
|
74
|
+
CircuitSwitch.run(close_if: -> { Date.today >= some_day }) do
|
75
|
+
# testing codes
|
76
|
+
end
|
77
|
+
```
|
78
|
+
|
79
|
+
Or when the code of concern has been called 1000 times:
|
80
|
+
|
81
|
+
```ruby
|
82
|
+
CircuitSwitch.run(close_if_reach_limit: true, limit_count: 1_000) do
|
74
83
|
# testing codes
|
75
84
|
end
|
76
85
|
```
|
@@ -102,15 +111,15 @@ When you just want to report, set your `reporter` to initializer and then call `
|
|
102
111
|
CircuitSwitch.report(if: some_condition)
|
103
112
|
```
|
104
113
|
|
105
|
-
`report` just reports
|
106
|
-
Same as `run`,
|
107
|
-
`report` receives optional arguments.
|
114
|
+
`report` just reports which line of code is called. It doesn't receive proc. It's useful for refactoring or removing dead codes.
|
115
|
+
Same as `run`, a set of options can be set. By default, this method does not send reports more than 10 times. The constant 10 comes from the table definition we have arbitrarily chosen. In case you need a larger number, specify it in the `limit_count` option, or alter default constraint on `circuit_switches.report_limit_count`.
|
108
116
|
|
109
|
-
- `
|
110
|
-
- `
|
111
|
-
- `
|
112
|
-
- `
|
113
|
-
|
117
|
+
- `key`: [String] The identifier to find record by. If `key` has not been passed, `circuit_switches.caller` is chosen as an alternative.
|
118
|
+
- `if`: [Boolean, Proc] Reports when the value of `if` is evaluated truthy (default: true)
|
119
|
+
- `stop_report_if`: [Boolean, Proc] Reports when the value of `stop_report_if` is evaluated falsy (default: false)
|
120
|
+
- `stop_report_if_reach_limit`: [Boolean] Stops reporting when `circuit_switches.report_count` has reached `circuit_switches.report_limit_count` (default: true)
|
121
|
+
- `limit_count`: [Integer] Mutates `circuit_switches.report_limit_count` whose value defined in schema is 10 by default. (default: nil)
|
122
|
+
Can't be set to 0 when `stop_report_if_reach_limit` is true.
|
114
123
|
|
115
124
|
To know about report is executed or not, you can get through `report?`.
|
116
125
|
Of course you can chain `report` and `run` or `open?`.
|
@@ -129,12 +138,31 @@ called_path: /app/services/greetings_service:21 block in validate
|
|
129
138
|
/app/controllers/greetings_controller.rb:93 create
|
130
139
|
```
|
131
140
|
|
141
|
+
## Test
|
142
|
+
|
143
|
+
To test, FactoryBot will look like this;
|
144
|
+
|
145
|
+
```ruby
|
146
|
+
FactoryBot.define do
|
147
|
+
factory :circuit_switch, class: 'CircuitSwitch::CircuitSwitch' do
|
148
|
+
sequence(:key) { |n| "/path/to/file:#{n}" }
|
149
|
+
sequence(:caller) { |n| "/path/to/file:#{n}" }
|
150
|
+
due_date { Date.tomorrow }
|
151
|
+
|
152
|
+
trait :initially_closed do
|
153
|
+
run_is_terminated { true }
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
```
|
158
|
+
|
132
159
|
## Task
|
133
160
|
|
134
|
-
When find a problem and you want to terminate running or reporting right now, execute a task with it's caller.
|
161
|
+
When find a problem and you want to terminate running or reporting right now, execute a task with it's caller.
|
162
|
+
You can specify either key or caller.
|
135
163
|
|
136
164
|
```
|
137
|
-
rake circuit_switch:terminate_to_run[
|
165
|
+
rake circuit_switch:terminate_to_run[your_key]
|
138
166
|
rake circuit_switch:terminate_to_report[/app/services/greetings_service:21 block in validate]
|
139
167
|
```
|
140
168
|
|
data/circuit_switch.gemspec
CHANGED
@@ -25,6 +25,7 @@ Gem::Specification.new do |spec|
|
|
25
25
|
|
26
26
|
spec.add_dependency 'activejob'
|
27
27
|
spec.add_dependency 'activerecord'
|
28
|
+
spec.add_dependency 'activesupport'
|
28
29
|
spec.add_development_dependency 'byebug'
|
29
30
|
spec.add_development_dependency 'sqlite3'
|
30
31
|
spec.add_development_dependency 'test-unit'
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require_relative 'core'
|
2
|
+
|
3
|
+
module CircuitSwitch
|
4
|
+
class Builder < Core
|
5
|
+
def initialize
|
6
|
+
super
|
7
|
+
@run = false
|
8
|
+
@reported = false
|
9
|
+
end
|
10
|
+
|
11
|
+
def assign_runner(
|
12
|
+
key: nil,
|
13
|
+
if: true,
|
14
|
+
close_if: false,
|
15
|
+
close_if_reach_limit: nil,
|
16
|
+
limit_count: nil,
|
17
|
+
initially_closed: false
|
18
|
+
)
|
19
|
+
@key = key
|
20
|
+
@run_if = binding.local_variable_get(:if)
|
21
|
+
@close_if = close_if
|
22
|
+
@close_if_reach_limit = close_if_reach_limit
|
23
|
+
@run_limit_count = limit_count
|
24
|
+
@initially_closed = initially_closed
|
25
|
+
end
|
26
|
+
|
27
|
+
def assign_reporter(
|
28
|
+
key: nil,
|
29
|
+
if: true,
|
30
|
+
stop_report_if: false,
|
31
|
+
stop_report_if_reach_limit: true,
|
32
|
+
limit_count: nil
|
33
|
+
)
|
34
|
+
@key = key
|
35
|
+
@report_if = binding.local_variable_get(:if)
|
36
|
+
@stop_report_if = stop_report_if
|
37
|
+
@stop_report_if_reach_limit = stop_report_if_reach_limit
|
38
|
+
@report_limit_count = limit_count
|
39
|
+
end
|
40
|
+
|
41
|
+
def run(key: nil, if: nil, close_if: nil, close_if_reach_limit: nil, limit_count: nil, initially_closed: nil, &block)
|
42
|
+
arguments = {
|
43
|
+
key: key,
|
44
|
+
if: binding.local_variable_get(:if),
|
45
|
+
close_if: close_if,
|
46
|
+
close_if_reach_limit: close_if_reach_limit,
|
47
|
+
limit_count: limit_count,
|
48
|
+
initially_closed: initially_closed,
|
49
|
+
}.select { |_, v| v }
|
50
|
+
assign_runner(**arguments)
|
51
|
+
execute_run(&block)
|
52
|
+
end
|
53
|
+
|
54
|
+
def report(key: nil, if: nil, stop_report_if: nil, stop_report_if_reach_limit: nil, limit_count: nil)
|
55
|
+
arguments = {
|
56
|
+
key: key,
|
57
|
+
if: binding.local_variable_get(:if),
|
58
|
+
stop_report_if: stop_report_if,
|
59
|
+
stop_report_if_reach_limit: stop_report_if_reach_limit,
|
60
|
+
limit_count: limit_count
|
61
|
+
}.select { |_, v| v }
|
62
|
+
assign_reporter(**arguments)
|
63
|
+
execute_report
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
data/lib/circuit_switch/core.rb
CHANGED
@@ -1,54 +1,59 @@
|
|
1
|
+
require_relative 'notification'
|
2
|
+
require_relative 'workers/reporter'
|
3
|
+
require_relative 'workers/run_count_updater'
|
4
|
+
|
1
5
|
module CircuitSwitch
|
2
6
|
class Core
|
3
7
|
delegate :config, to: ::CircuitSwitch
|
8
|
+
attr_reader :key, :run_if, :close_if, :close_if_reach_limit, :run_limit_count, :initially_closed,
|
9
|
+
:report_if, :stop_report_if, :stop_report_if_reach_limit, :report_limit_count
|
4
10
|
|
5
|
-
def
|
6
|
-
if
|
7
|
-
close_if: false,
|
8
|
-
close_if_reach_limit: nil,
|
9
|
-
limit_count: nil,
|
10
|
-
&block
|
11
|
-
)
|
12
|
-
if close_if_reach_limit && limit_count == 0
|
11
|
+
def execute_run(&block)
|
12
|
+
if close_if_reach_limit && run_limit_count == 0
|
13
13
|
raise CircuitSwitchError.new('Can\'t set limit_count to 0 when close_if_reach_limit is true')
|
14
14
|
end
|
15
15
|
if close_if_reach_limit.nil?
|
16
|
-
Logger.new($stdout).
|
17
|
-
close_if_reach_limit = false
|
16
|
+
Logger.new($stdout).info('Default value for close_if_reach_limit is modified from true to false at ver 0.2.0.')
|
17
|
+
@close_if_reach_limit = false
|
18
18
|
end
|
19
|
-
|
20
|
-
return self if
|
19
|
+
|
20
|
+
return self if evaluate(close_if) || !evaluate(run_if)
|
21
|
+
return self if close_if_reach_limit && switch.reached_run_limit?(run_limit_count)
|
21
22
|
return self if switch.run_is_terminated?
|
22
23
|
|
23
|
-
|
24
|
+
unless switch.new_record? && initially_closed
|
25
|
+
yield
|
26
|
+
@run = true
|
27
|
+
end
|
28
|
+
self
|
29
|
+
ensure
|
24
30
|
RunCountUpdater.perform_later(
|
25
|
-
|
31
|
+
key: key,
|
32
|
+
limit_count: run_limit_count,
|
26
33
|
called_path: called_path,
|
27
|
-
reported: reported
|
34
|
+
reported: reported?,
|
35
|
+
initially_closed: initially_closed
|
28
36
|
)
|
29
|
-
@run = true
|
30
|
-
self
|
31
37
|
end
|
32
38
|
|
33
|
-
def
|
34
|
-
if: true,
|
35
|
-
stop_report_if: false,
|
36
|
-
stop_report_if_reach_limit: true,
|
37
|
-
limit_count: nil
|
38
|
-
)
|
39
|
+
def execute_report
|
39
40
|
if config.reporter.nil?
|
40
41
|
raise CircuitSwitchError.new('Set config.reporter.')
|
41
42
|
end
|
42
|
-
if
|
43
|
+
if config.reporter.arity == 1
|
44
|
+
Logger.new($stdout).info('config.reporter now receives 2 arguments. Improve your `config/initialzers/circuit_switch.rb`.')
|
45
|
+
end
|
46
|
+
if stop_report_if_reach_limit && report_limit_count == 0
|
43
47
|
raise CircuitSwitchError.new('Can\'t set limit_count to 0 when stop_report_if_reach_limit is true')
|
44
48
|
end
|
45
49
|
return self unless config.enable_report?
|
46
|
-
return self if evaluate(stop_report_if) || !evaluate(
|
50
|
+
return self if evaluate(stop_report_if) || !evaluate(report_if)
|
47
51
|
return self if switch.report_is_terminated?
|
48
|
-
return self if stop_report_if_reach_limit && switch.reached_report_limit?(
|
52
|
+
return self if stop_report_if_reach_limit && switch.reached_report_limit?(report_limit_count)
|
49
53
|
|
50
54
|
Reporter.perform_later(
|
51
|
-
|
55
|
+
key: key,
|
56
|
+
limit_count: report_limit_count,
|
52
57
|
called_path: called_path,
|
53
58
|
run: run?
|
54
59
|
)
|
@@ -58,18 +63,24 @@ module CircuitSwitch
|
|
58
63
|
|
59
64
|
# @return [Boolean]
|
60
65
|
def run?
|
61
|
-
|
66
|
+
@run
|
62
67
|
end
|
63
68
|
|
64
69
|
# @return [Boolean]
|
65
70
|
def reported?
|
66
|
-
|
71
|
+
@reported
|
67
72
|
end
|
68
73
|
|
69
74
|
private
|
70
75
|
|
71
76
|
def switch
|
72
|
-
@switch
|
77
|
+
return @switch if defined? @switch
|
78
|
+
|
79
|
+
if key
|
80
|
+
@switch = CircuitSwitch.find_or_initialize_by(key: key)
|
81
|
+
else
|
82
|
+
@switch = CircuitSwitch.find_or_initialize_by(caller: called_path)
|
83
|
+
end
|
73
84
|
end
|
74
85
|
|
75
86
|
def called_path
|
@@ -1,5 +1,13 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
|
1
3
|
module CircuitSwitch
|
2
4
|
class CircuitSwitch < ::ActiveRecord::Base
|
5
|
+
validates :key, uniqueness: true
|
6
|
+
|
7
|
+
after_initialize do |switch|
|
8
|
+
switch.key ||= switch.caller
|
9
|
+
end
|
10
|
+
|
3
11
|
def assign(run_limit_count: nil, report_limit_count: nil)
|
4
12
|
self.run_limit_count = run_limit_count if run_limit_count
|
5
13
|
self.report_limit_count = report_limit_count if report_limit_count
|
@@ -22,16 +30,17 @@ module CircuitSwitch
|
|
22
30
|
end
|
23
31
|
end
|
24
32
|
|
25
|
-
def increment_run_count
|
33
|
+
def increment_run_count!
|
26
34
|
with_writable { update!(run_count: run_count + 1) }
|
27
35
|
end
|
28
36
|
|
29
|
-
def increment_report_count
|
37
|
+
def increment_report_count!
|
30
38
|
with_writable { update!(report_count: report_count + 1) }
|
31
39
|
end
|
32
40
|
|
33
41
|
def message
|
34
|
-
|
42
|
+
process = key == caller ? 'Watching process' : "Process for '#{key}'"
|
43
|
+
"#{process} is called for #{report_count}th. Report until for #{report_limit_count}th."
|
35
44
|
end
|
36
45
|
|
37
46
|
private
|
@@ -1,40 +1,40 @@
|
|
1
1
|
namespace :circuit_switch do
|
2
2
|
desc 'Update run_is_terminated to true to close circuit'
|
3
|
-
task :terminate_to_run, ['
|
4
|
-
|
5
|
-
puts "Start to update run_is_terminated of circuit_switch for '#{
|
3
|
+
task :terminate_to_run, ['key_or_caller'] => :environment do |_, arg|
|
4
|
+
key_or_caller = arg[:key_or_caller]
|
5
|
+
puts "Start to update run_is_terminated of circuit_switch for '#{key_or_caller}' to true."
|
6
6
|
sleep(3)
|
7
7
|
|
8
|
-
switch = CircuitSwitch::CircuitSwitch.find_by!(caller:
|
8
|
+
switch = CircuitSwitch::CircuitSwitch.find_by(key: key_or_caller) || CircuitSwitch::CircuitSwitch.find_by!(caller: key_or_caller)
|
9
9
|
puts "circuit_switch is found. id: #{switch.id}."
|
10
10
|
|
11
11
|
switch.update(run_is_terminated: true)
|
12
|
-
puts "Updated run_is_terminated of circuit_switch for '#{
|
12
|
+
puts "Updated run_is_terminated of circuit_switch for '#{key_or_caller}' to true."
|
13
13
|
end
|
14
14
|
|
15
15
|
desc 'Update report_is_terminated to true to stop reporting'
|
16
|
-
task :terminate_to_report, ['
|
17
|
-
|
18
|
-
puts "Start to update report_is_terminated of circuit_switch for '#{
|
16
|
+
task :terminate_to_report, ['key_or_caller'] => :environment do |_, arg|
|
17
|
+
key_or_caller = arg[:key_or_caller]
|
18
|
+
puts "Start to update report_is_terminated of circuit_switch for '#{key_or_caller}' to true."
|
19
19
|
sleep(3)
|
20
20
|
|
21
|
-
switch = CircuitSwitch::CircuitSwitch.find_by!(caller:
|
21
|
+
switch = CircuitSwitch::CircuitSwitch.find_by(key: key_or_caller) || CircuitSwitch::CircuitSwitch.find_by!(caller: key_or_caller)
|
22
22
|
puts "circuit_switch is found. id: #{switch.id}."
|
23
23
|
|
24
24
|
switch.update(report_is_terminated: true)
|
25
|
-
puts "Updated report_is_terminated of circuit_switch for '#{
|
25
|
+
puts "Updated report_is_terminated of circuit_switch for '#{key_or_caller}' to true."
|
26
26
|
end
|
27
27
|
|
28
28
|
desc 'Delete switch'
|
29
|
-
task :delete_switch, ['
|
30
|
-
|
31
|
-
puts "Start to delete circuit_switch for '#{
|
29
|
+
task :delete_switch, ['key_or_caller'] => :environment do |_, arg|
|
30
|
+
key_or_caller = arg[:key_or_caller]
|
31
|
+
puts "Start to delete circuit_switch for '#{key_or_caller}'."
|
32
32
|
sleep(3)
|
33
33
|
|
34
|
-
switch = CircuitSwitch::CircuitSwitch.find_by!(caller:
|
34
|
+
switch = CircuitSwitch::CircuitSwitch.find_by(key: key_or_caller) || CircuitSwitch::CircuitSwitch.find_by!(caller: key_or_caller)
|
35
35
|
puts "circuit_switch is found. id: #{switch.id}."
|
36
36
|
|
37
37
|
switch.destroy!
|
38
|
-
puts "Successfully deleted circuit_switch for '#{
|
38
|
+
puts "Successfully deleted circuit_switch for '#{key_or_caller}'."
|
39
39
|
end
|
40
40
|
end
|
@@ -10,7 +10,7 @@ module CircuitSwitch
|
|
10
10
|
circuit_switches = CircuitSwitch.where('due_date <= ?', Date.today).order(id: :asc)
|
11
11
|
if circuit_switches.present?
|
12
12
|
message = "Due date has come! Let's consider about removing switches and cleaning up code! :)\n" +
|
13
|
-
circuit_switches.map { |switch| "id: #{switch.id}, caller: '#{switch.caller}'
|
13
|
+
circuit_switches.map { |switch| "id: #{switch.id}, key: '#{switch.key}', caller: '#{switch.caller}', created_at: #{switch.created_at}" }.join("\n")
|
14
14
|
config.due_date_notifier.call(message)
|
15
15
|
else
|
16
16
|
switches_count = CircuitSwitch.all.size
|
@@ -1,21 +1,38 @@
|
|
1
|
+
require 'active_job'
|
2
|
+
require 'active_support/core_ext/module/delegation'
|
3
|
+
|
1
4
|
module CircuitSwitch
|
2
5
|
class Reporter < ::ActiveJob::Base
|
3
6
|
delegate :config, to: ::CircuitSwitch
|
4
7
|
|
5
|
-
def perform(limit_count:, called_path:, run:)
|
6
|
-
circuit_switch
|
7
|
-
if run
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
8
|
+
def perform(key:, limit_count:, called_path:, run:)
|
9
|
+
# Wait for RunCountUpdater saves circuit_switch
|
10
|
+
sleep(3) if run
|
11
|
+
|
12
|
+
first_raise = true
|
13
|
+
begin
|
14
|
+
circuit_switch = key ? CircuitSwitch.find_by(key: key) : CircuitSwitch.find_by(caller: called_path)
|
15
|
+
if run && circuit_switch.nil?
|
16
|
+
raise ActiveRecord::RecordNotFound.new('Couldn\'t find CircuitSwitch::CircuitSwitch')
|
17
|
+
end
|
18
|
+
|
19
|
+
circuit_switch ||= CircuitSwitch.new(key: key, caller: called_path)
|
20
|
+
circuit_switch.due_date ||= config.due_date
|
21
|
+
circuit_switch.assign(report_limit_count: limit_count).increment_report_count!
|
22
|
+
raise CalledNotification.new(circuit_switch.message)
|
23
|
+
rescue ActiveRecord::RecordInvalid => e
|
24
|
+
raise e unless first_raise
|
25
|
+
|
26
|
+
first_raise = false
|
27
|
+
sleep(2)
|
28
|
+
retry
|
29
|
+
rescue CalledNotification => notification
|
30
|
+
if config.reporter.arity == 1
|
31
|
+
config.reporter.call(notification.to_message(called_path: called_path))
|
32
|
+
else
|
33
|
+
config.reporter.call(notification.to_message(called_path: called_path), notification)
|
34
|
+
end
|
13
35
|
end
|
14
|
-
circuit_switch.due_date ||= config.due_date
|
15
|
-
circuit_switch.assign(report_limit_count: limit_count).increment_report_count
|
16
|
-
raise CalledNotification.new(circuit_switch.message)
|
17
|
-
rescue CalledNotification => notification
|
18
|
-
config.reporter.call(notification.to_message(called_path: called_path))
|
19
36
|
end
|
20
37
|
end
|
21
38
|
end
|
@@ -1,18 +1,31 @@
|
|
1
|
+
require 'active_job'
|
2
|
+
require 'active_support/core_ext/module/delegation'
|
3
|
+
|
1
4
|
module CircuitSwitch
|
2
5
|
class RunCountUpdater < ::ActiveJob::Base
|
3
6
|
delegate :config, to: ::CircuitSwitch
|
4
7
|
|
5
|
-
def perform(limit_count:, called_path:, reported:)
|
6
|
-
circuit_switch
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
8
|
+
def perform(key:, limit_count:, called_path:, reported:, initially_closed:)
|
9
|
+
# Wait for Reporter saves circuit_switch
|
10
|
+
sleep(3) if reported
|
11
|
+
|
12
|
+
first_raise = true
|
13
|
+
begin
|
14
|
+
circuit_switch = key ? CircuitSwitch.find_by(key: key) : CircuitSwitch.find_by(caller: called_path)
|
15
|
+
if reported && circuit_switch.nil?
|
16
|
+
raise ActiveRecord::RecordNotFound.new('Couldn\'t find CircuitSwitch::CircuitSwitch')
|
13
17
|
end
|
14
|
-
|
15
|
-
|
18
|
+
|
19
|
+
circuit_switch ||= CircuitSwitch.new(key: key, caller: called_path, run_is_terminated: initially_closed)
|
20
|
+
circuit_switch.due_date ||= config.due_date
|
21
|
+
circuit_switch.assign(run_limit_count: limit_count).increment_run_count!
|
22
|
+
rescue ActiveRecord::RecordInvalid => e
|
23
|
+
raise e unless first_raise
|
24
|
+
|
25
|
+
first_raise = false
|
26
|
+
sleep(2)
|
27
|
+
retry
|
28
|
+
end
|
16
29
|
end
|
17
30
|
end
|
18
31
|
end
|
data/lib/circuit_switch.rb
CHANGED
@@ -1,12 +1,9 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
require "circuit_switch/workers/due_date_notifier"
|
8
|
-
require "circuit_switch/workers/reporter"
|
9
|
-
require "circuit_switch/workers/run_count_updater"
|
1
|
+
require_relative 'circuit_switch/configuration'
|
2
|
+
require_relative 'circuit_switch/builder'
|
3
|
+
require_relative 'circuit_switch/orm/active_record/circuit_switch'
|
4
|
+
require_relative 'circuit_switch/railtie' if defined?(Rails::Railtie)
|
5
|
+
require_relative 'circuit_switch/version'
|
6
|
+
require_relative 'circuit_switch/workers/due_date_notifier'
|
10
7
|
|
11
8
|
module CircuitSwitch
|
12
9
|
class << self
|
@@ -18,73 +15,69 @@ module CircuitSwitch
|
|
18
15
|
@config ||= Configuration.new
|
19
16
|
end
|
20
17
|
|
18
|
+
# @param key [String] Named key to find switch instead of caller
|
21
19
|
# @param if [Boolean, Proc] Call proc when `if` is truthy (default: true)
|
22
20
|
# @param close_if [Boolean, Proc] Call proc when `close_if` is falsy (default: false)
|
23
21
|
# @param close_if_reach_limit [Boolean] Stop calling proc when run count reaches limit (default: false)
|
24
22
|
# @param limit_count [Integer] Limit count. Use `run_limit_count` default value if it's nil
|
25
23
|
# Can't be set 0 when `close_if_reach_limit` is true (default: nil)
|
24
|
+
# @param initially_closed [Boolean] Create switch with terminated mode (default: false)
|
26
25
|
# @param [Proc] block
|
27
|
-
def run(
|
28
|
-
|
29
|
-
|
30
|
-
close_if_reach_limit: nil,
|
31
|
-
limit_count: nil,
|
32
|
-
&block
|
33
|
-
)
|
34
|
-
Core.new.run(
|
26
|
+
def run(key: nil, if: nil, close_if: nil, close_if_reach_limit: nil, limit_count: nil, initially_closed: nil, &block)
|
27
|
+
arguments = {
|
28
|
+
key: key,
|
35
29
|
if: binding.local_variable_get(:if),
|
36
30
|
close_if: close_if,
|
37
31
|
close_if_reach_limit: close_if_reach_limit,
|
38
32
|
limit_count: limit_count,
|
39
|
-
|
40
|
-
|
33
|
+
initially_closed: initially_closed,
|
34
|
+
}.select { |_, v| v }
|
35
|
+
Builder.new.run(**arguments, &block)
|
41
36
|
end
|
42
37
|
|
38
|
+
# @param key [String] Named key to find switch instead of caller
|
43
39
|
# @param if [Boolean, Proc] Report when `if` is truthy (default: true)
|
44
40
|
# @param stop_report_if [Boolean, Proc] Report when `close_if` is falsy (default: false)
|
45
41
|
# @param stop_report_if_reach_limit [Boolean] Stop reporting when reported count reaches limit (default: true)
|
46
42
|
# @param limit_count [Integer] Limit count. Use `report_limit_count` default value if it's nil
|
47
43
|
# Can't be set 0 when `stop_report_if_reach_limit` is true (default: nil)
|
48
|
-
def report(
|
49
|
-
if: true,
|
50
|
-
stop_report_if: false,
|
51
|
-
stop_report_if_reach_limit: true,
|
52
|
-
limit_count: nil
|
53
|
-
)
|
44
|
+
def report(key: nil, if: nil, stop_report_if: nil, stop_report_if_reach_limit: nil, limit_count: nil)
|
54
45
|
if block_given?
|
55
46
|
raise ArgumentError.new('CircuitSwitch.report doesn\'t receive block. Use CircuitSwitch.run if you want to pass block.')
|
56
47
|
end
|
57
48
|
|
58
|
-
|
49
|
+
arguments = {
|
50
|
+
key: key,
|
59
51
|
if: binding.local_variable_get(:if),
|
60
52
|
stop_report_if: stop_report_if,
|
61
53
|
stop_report_if_reach_limit: stop_report_if_reach_limit,
|
62
54
|
limit_count: limit_count
|
63
|
-
|
55
|
+
}.select { |_, v| v }
|
56
|
+
Builder.new.report(**arguments)
|
64
57
|
end
|
65
58
|
|
66
59
|
# Syntax sugar for `CircuitSwitch.run`
|
60
|
+
# @param key [String] Named key to find switch instead of caller
|
67
61
|
# @param if [Boolean, Proc] `CircuitSwitch.run` is runnable when `if` is truthy (default: true)
|
68
62
|
# @param close_if [Boolean, Proc] `CircuitSwitch.run` is runnable when `close_if` is falsy (default: false)
|
69
63
|
# @param close_if_reach_limit [Boolean] `CircuitSwitch.run` is NOT runnable when run count reaches limit (default: true)
|
70
64
|
# @param limit_count [Integer] Limit count. Use `run_limit_count` default value if it's nil. Can't be set 0 (default: nil)
|
65
|
+
# @param initially_closed [Boolean] Create switch with terminated mode (default: false)
|
71
66
|
# @return [Boolean]
|
72
|
-
def open?(
|
73
|
-
if: true,
|
74
|
-
close_if: false,
|
75
|
-
close_if_reach_limit: true,
|
76
|
-
limit_count: nil
|
77
|
-
)
|
67
|
+
def open?(key: nil, if: nil, close_if: nil, close_if_reach_limit: nil, limit_count: nil, initially_closed: nil)
|
78
68
|
if block_given?
|
79
69
|
raise ArgumentError.new('CircuitSwitch.open doesn\'t receive block. Use CircuitSwitch.run if you want to pass block.')
|
80
70
|
end
|
81
71
|
|
82
|
-
|
72
|
+
arguments = {
|
73
|
+
key: key,
|
83
74
|
if: binding.local_variable_get(:if),
|
84
75
|
close_if: close_if,
|
85
76
|
close_if_reach_limit: close_if_reach_limit,
|
86
|
-
limit_count: limit_count
|
87
|
-
|
77
|
+
limit_count: limit_count,
|
78
|
+
initially_closed: initially_closed,
|
79
|
+
}.select { |_, v| v }
|
80
|
+
Builder.new.run(**arguments) {}.run?
|
88
81
|
end
|
89
82
|
end
|
90
83
|
end
|
@@ -4,9 +4,19 @@ module CircuitSwitch
|
|
4
4
|
class MigrationGenerator < ActiveRecord::Generators::Base
|
5
5
|
desc 'Create a migration to manage circuit switches state'
|
6
6
|
source_root File.expand_path('templates', __dir__)
|
7
|
+
argument :migration_type, required: false, type: :array, default: ['create'],
|
8
|
+
desc: 'Type of migration to create or add key column or make key unique. By default to create.',
|
9
|
+
banner: 'create or add_key'
|
7
10
|
|
8
11
|
def generate_migration
|
9
|
-
|
12
|
+
case migration_type
|
13
|
+
when ['add_key']
|
14
|
+
migration_template 'add_key.rb.erb', 'db/migrate/add_key_to_circuit_switches.rb', migration_version: migration_version
|
15
|
+
when ['make_key_unique']
|
16
|
+
migration_template 'make_key_unique.rb.erb', 'db/migrate/make_key_unique_for_circuit_switches.rb', migration_version: migration_version
|
17
|
+
else
|
18
|
+
migration_template 'migration.rb.erb', 'db/migrate/create_circuit_switches.rb', migration_version: migration_version
|
19
|
+
end
|
10
20
|
end
|
11
21
|
|
12
22
|
def migration_version
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class AddKeyToCircuitSwitches < ActiveRecord::Migration<%= migration_version %>
|
2
|
+
def up
|
3
|
+
add_column :circuit_switches, :key, :string, after: :id
|
4
|
+
CircuitSwitch::CircuitSwitch.all.each { |switch| switch.update_column(:key, switch.caller) }
|
5
|
+
change_column_null :circuit_switches, :key, false
|
6
|
+
add_index :circuit_switches, :key
|
7
|
+
end
|
8
|
+
|
9
|
+
def down
|
10
|
+
remove_index :circuit_switches, :key
|
11
|
+
remove_column :circuit_switches, :key
|
12
|
+
end
|
13
|
+
end
|
@@ -2,7 +2,8 @@
|
|
2
2
|
|
3
3
|
CircuitSwitch.configure do |config|
|
4
4
|
# Specify proc to call your report tool: like;
|
5
|
-
# config.reporter = -> (message) { Bugsnag.notify(
|
5
|
+
# config.reporter = -> (message, error) { Bugsnag.notify(error) }
|
6
|
+
# config.reporter = -> (message, error) { Sentry::Rails.capture_message(message) }
|
6
7
|
config.reporter = nil
|
7
8
|
|
8
9
|
# Condition to report
|
@@ -16,6 +17,9 @@ CircuitSwitch.configure do |config|
|
|
16
17
|
# Excluded paths to report
|
17
18
|
# config.silent_paths = [CIRCUIT_SWITCH]
|
18
19
|
|
20
|
+
# Alias column name for circuit_switches.key through alias_attribute
|
21
|
+
# config.key_column_name = :key
|
22
|
+
|
19
23
|
# Notifier to notify circuit_switch's due_date come and it's time to clean code!
|
20
24
|
# Specify proc to call your report tool: like;
|
21
25
|
# config.due_date_notifier = -> (message) { Slack::Web::Client.new.chat_postMessage(channel: '#your_channel', text: message) }
|
@@ -26,10 +30,10 @@ CircuitSwitch.configure do |config|
|
|
26
30
|
|
27
31
|
# Option to contain error backtrace for report
|
28
32
|
# You don't need backtrace when you report to some bug report tool.
|
29
|
-
# You may
|
33
|
+
# You may want backtrace when reporting to a plain feed; e.g. Slack or email.
|
30
34
|
# config.with_backtrace = false
|
31
35
|
|
32
|
-
#
|
36
|
+
# Allowed backtrace paths to report
|
33
37
|
# Specify with `with_backtrace` option.
|
34
38
|
# Allowed all paths when set `[]`.
|
35
39
|
# config.allowed_backtrace_paths = [Dir.pwd]
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class MakeKeyUniqueForCircuitSwitches < ActiveRecord::Migration<%= migration_version %>
|
2
|
+
def up
|
3
|
+
remove_index :circuit_switches, :key
|
4
|
+
add_index :circuit_switches, :key, unique: true
|
5
|
+
end
|
6
|
+
|
7
|
+
def down
|
8
|
+
remove_index :circuit_switches, :key
|
9
|
+
add_index :circuit_switches, :key
|
10
|
+
end
|
11
|
+
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
class CreateCircuitSwitches < ActiveRecord::Migration<%= migration_version %>
|
2
2
|
def change
|
3
3
|
create_table :circuit_switches do |t|
|
4
|
+
t.string :key, null: false
|
4
5
|
t.string :caller, null: false
|
5
6
|
t.integer :run_count, default: 0, null: false
|
6
7
|
t.integer :run_limit_count, default: 10, null: false
|
@@ -11,5 +12,7 @@ class CreateCircuitSwitches < ActiveRecord::Migration<%= migration_version %>
|
|
11
12
|
t.date :due_date, null: false
|
12
13
|
t.timestamps
|
13
14
|
end
|
15
|
+
|
16
|
+
add_index :circuit_switches, [:key], unique: true
|
14
17
|
end
|
15
18
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: circuit_switch
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- makicamel
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-11-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activejob
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: activesupport
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: byebug
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -114,6 +128,7 @@ files:
|
|
114
128
|
- bin/setup
|
115
129
|
- circuit_switch.gemspec
|
116
130
|
- lib/circuit_switch.rb
|
131
|
+
- lib/circuit_switch/builder.rb
|
117
132
|
- lib/circuit_switch/configuration.rb
|
118
133
|
- lib/circuit_switch/core.rb
|
119
134
|
- lib/circuit_switch/notification.rb
|
@@ -128,7 +143,9 @@ files:
|
|
128
143
|
- lib/circuit_switch/workers/run_count_updater.rb
|
129
144
|
- lib/generators/circuit_switch/install_generator.rb
|
130
145
|
- lib/generators/circuit_switch/migration_generator.rb
|
146
|
+
- lib/generators/circuit_switch/templates/add_key.rb.erb
|
131
147
|
- lib/generators/circuit_switch/templates/initializer.rb
|
148
|
+
- lib/generators/circuit_switch/templates/make_key_unique.rb.erb
|
132
149
|
- lib/generators/circuit_switch/templates/migration.rb.erb
|
133
150
|
homepage: https://github.com/makicamel/circuit_switch
|
134
151
|
licenses:
|