circuit_switch 0.1.2 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/main.yml +27 -0
- data/CHANGELOG.md +51 -1
- data/README.md +31 -6
- data/Rakefile +9 -1
- 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 +42 -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 +2 -2
- 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 +26 -13
- data/lib/circuit_switch/workers/run_count_updater.rb +23 -10
- data/lib/circuit_switch.rb +30 -37
- 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 +5 -2
- 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 +20 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6a00a04ad121a8f40a84f78a55e769aaa8f3fc185ac58fab51ddff11a0678e28
|
4
|
+
data.tar.gz: '06189169b6959b97e8a33617f2d9e054f9acf3d55bce2833b39a5f6567a061c6'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b63203a04cb3a37e4c6ac265eb8283fdde5b5cb5990c4234bb57876d72c5c26e48ade13907373046dc9f4b8f943f8c6a34e8c6957bceae9ba3857ca087c9c033
|
7
|
+
data.tar.gz: ff59240799e6841334eaffcaa76706cd78268804f8dc263da2c57dfd2bdc480264768ba614fb4102186fa483750ff36eb7c2c0bcc87eb6836f70c0025bcd0361
|
@@ -0,0 +1,27 @@
|
|
1
|
+
name: CI
|
2
|
+
|
3
|
+
on: [push,pull_request]
|
4
|
+
|
5
|
+
jobs:
|
6
|
+
build:
|
7
|
+
strategy:
|
8
|
+
fail-fast: false
|
9
|
+
matrix:
|
10
|
+
os: [ubuntu-latest, windows-latest, macos-latest]
|
11
|
+
ruby: [2.3, 2.4, 2.5, 2.6, 2.7, 3.0, head, truffleruby]
|
12
|
+
exclude:
|
13
|
+
- os: windows-latest
|
14
|
+
ruby: head
|
15
|
+
- os: windows-latest
|
16
|
+
ruby: truffleruby
|
17
|
+
runs-on: ${{ matrix.os }}
|
18
|
+
steps:
|
19
|
+
- uses: actions/checkout@v2
|
20
|
+
- name: Set up Ruby
|
21
|
+
uses: ruby/setup-ruby@v1
|
22
|
+
with:
|
23
|
+
ruby-version: ${{ matrix.ruby }}
|
24
|
+
bundler-cache: true
|
25
|
+
- name: Run the default task
|
26
|
+
run: |
|
27
|
+
bundle exec rake
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,56 @@
|
|
1
|
+
## 0.3.0
|
2
|
+
|
3
|
+
### Breaking Changes
|
4
|
+
|
5
|
+
* Modify `key` to unique by default.
|
6
|
+
To migrate, run next.
|
7
|
+
|
8
|
+
```
|
9
|
+
rails generate circuit_switch:migration circuit_switch make_key_unique
|
10
|
+
rails db:migrate
|
11
|
+
```
|
12
|
+
|
13
|
+
### Changes
|
14
|
+
|
15
|
+
* Fix to save switch when block for `CircuitSwitch.run` raises error.
|
16
|
+
|
17
|
+
## 0.2.2
|
18
|
+
|
19
|
+
### New features
|
20
|
+
|
21
|
+
* Add `key_column_name` to configuration for aliasing `circuit_switches.key`.
|
22
|
+
|
23
|
+
### Changes
|
24
|
+
|
25
|
+
* Declare dependent on ActiveSupport instead of implicitly dependent.
|
26
|
+
|
27
|
+
## 0.2.1
|
28
|
+
|
29
|
+
### New features
|
30
|
+
|
31
|
+
* Add `initially_closed` option to `run` and `open?`.
|
32
|
+
* Add `key` argument for easy handling for human more than caller.
|
33
|
+
To migrate, run next.
|
34
|
+
|
35
|
+
```
|
36
|
+
rails generate circuit_switch:migration circuit_switch add_key
|
37
|
+
rails db:migrate
|
38
|
+
```
|
39
|
+
|
40
|
+
### Changes
|
41
|
+
|
42
|
+
* Modify log level from warn to info when default value for `close_if_reach_limit` is used.
|
43
|
+
* Suppress warning that ivar is not initialized.
|
44
|
+
|
45
|
+
## 0.2.0
|
46
|
+
|
47
|
+
### Breaking Changes
|
48
|
+
|
49
|
+
* Modify default value of `CircuitSwitch.run` argument `close_if_reach_limit` from true to false.
|
50
|
+
|
1
51
|
## 0.1.2
|
2
52
|
|
3
|
-
* Modify `CircuitSwitch.open?`
|
53
|
+
* Modify `CircuitSwitch.open?` receives same arguments as `CircuitSwitch.run`
|
4
54
|
|
5
55
|
## 0.1.1
|
6
56
|
|
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
|
@@ -57,14 +57,18 @@ end
|
|
57
57
|
```
|
58
58
|
|
59
59
|
`run` calls received proc, and when conditions are met, closes it's circuit.
|
60
|
-
To switch circuit opening and closing, some conditions can be set. By default, the circuit is
|
60
|
+
To switch circuit opening and closing, some conditions can be set. By default, the circuit is always opened.
|
61
|
+
You can also set `limit_count` to close circuit when reached the specified count. Default limit_count is 10. To change this default value, modify `circuit_switches.run_limit_count` default value in the migration file.
|
61
62
|
`run` receives optional arguments.
|
62
63
|
|
64
|
+
- `key`: [String] Named key to find switch instead of caller
|
65
|
+
If no key passed, use caller.
|
63
66
|
- `if`: [Boolean, Proc] Call proc when `if` is truthy (default: true)
|
64
67
|
- `close_if`: [Boolean, Proc] Call proc when `close_if` is falsy (default: false)
|
65
|
-
- `close_if_reach_limit`: [Boolean] Stop calling proc when run count reaches limit (default:
|
68
|
+
- `close_if_reach_limit`: [Boolean] Stop calling proc when run count reaches limit (default: false)
|
66
69
|
- `limit_count`: [Integer] Limit count. Use `run_limit_count` default value if it's nil (default: nil)
|
67
70
|
Can't be set 0 when `close_if_reach_limit` is true
|
71
|
+
- `initially_closed`: [Boolean] Create switch with terminated mode (default: false)
|
68
72
|
|
69
73
|
To close the circuit at specific date or when called 1000 times, code goes like:
|
70
74
|
|
@@ -83,7 +87,7 @@ unless circuit_open
|
|
83
87
|
end
|
84
88
|
```
|
85
89
|
|
86
|
-
`CircuitSwitch.run.run?` has syntax sugar. `open
|
90
|
+
`CircuitSwitch.run.run?` has syntax sugar. `open?` doesn't receive proc.
|
87
91
|
|
88
92
|
```ruby
|
89
93
|
if CircuitSwitch.open?
|
@@ -105,6 +109,8 @@ CircuitSwitch.report(if: some_condition)
|
|
105
109
|
Same as `run`, some conditions can be set. By default, reporting is stopped when reached the specified count. The default count is 10. To change this default value, modify `circuit_switches.report_limit_count` default value in the migration file.
|
106
110
|
`report` receives optional arguments.
|
107
111
|
|
112
|
+
- `key`: [String] Named key to find switch instead of caller
|
113
|
+
If no key passed, use caller.
|
108
114
|
- `if`: [Boolean, Proc] Report when `if` is truthy (default: true)
|
109
115
|
- `stop_report_if`: [Boolean, Proc] Report when `close_if` is falsy (default: false)
|
110
116
|
- `stop_report_if_reach_limit`: [Boolean] Stop reporting when reported count reaches limit (default: true)
|
@@ -128,12 +134,31 @@ called_path: /app/services/greetings_service:21 block in validate
|
|
128
134
|
/app/controllers/greetings_controller.rb:93 create
|
129
135
|
```
|
130
136
|
|
137
|
+
## Test
|
138
|
+
|
139
|
+
To test, FactoryBot will look like this;
|
140
|
+
|
141
|
+
```ruby
|
142
|
+
FactoryBot.define do
|
143
|
+
factory :circuit_switch, class: 'CircuitSwitch::CircuitSwitch' do
|
144
|
+
sequence(:key) { |n| "/path/to/file:#{n}" }
|
145
|
+
sequence(:caller) { |n| "/path/to/file:#{n}" }
|
146
|
+
due_date { Date.tomorrow }
|
147
|
+
|
148
|
+
trait :initially_closed do
|
149
|
+
run_is_terminated { true }
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
```
|
154
|
+
|
131
155
|
## Task
|
132
156
|
|
133
|
-
When find a problem and you want to terminate running or reporting right now, execute a task with it's caller.
|
157
|
+
When find a problem and you want to terminate running or reporting right now, execute a task with it's caller.
|
158
|
+
You can specify either key or caller.
|
134
159
|
|
135
160
|
```
|
136
|
-
rake circuit_switch:terminate_to_run[
|
161
|
+
rake circuit_switch:terminate_to_run[your_key]
|
137
162
|
rake circuit_switch:terminate_to_report[/app/services/greetings_service:21 block in validate]
|
138
163
|
```
|
139
164
|
|
data/Rakefile
CHANGED
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,50 +1,56 @@
|
|
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: true,
|
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
|
-
|
16
|
-
|
15
|
+
if close_if_reach_limit.nil?
|
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
|
+
end
|
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)
|
17
22
|
return self if switch.run_is_terminated?
|
18
23
|
|
19
|
-
|
24
|
+
unless switch.new_record? && initially_closed
|
25
|
+
yield
|
26
|
+
@run = true
|
27
|
+
end
|
28
|
+
self
|
29
|
+
ensure
|
20
30
|
RunCountUpdater.perform_later(
|
21
|
-
|
31
|
+
key: key,
|
32
|
+
limit_count: run_limit_count,
|
22
33
|
called_path: called_path,
|
23
|
-
reported: reported
|
34
|
+
reported: reported?,
|
35
|
+
initially_closed: initially_closed
|
24
36
|
)
|
25
|
-
@run = true
|
26
|
-
self
|
27
37
|
end
|
28
38
|
|
29
|
-
def
|
30
|
-
if: true,
|
31
|
-
stop_report_if: false,
|
32
|
-
stop_report_if_reach_limit: true,
|
33
|
-
limit_count: nil
|
34
|
-
)
|
39
|
+
def execute_report
|
35
40
|
if config.reporter.nil?
|
36
41
|
raise CircuitSwitchError.new('Set config.reporter.')
|
37
42
|
end
|
38
|
-
if stop_report_if_reach_limit &&
|
43
|
+
if stop_report_if_reach_limit && report_limit_count == 0
|
39
44
|
raise CircuitSwitchError.new('Can\'t set limit_count to 0 when stop_report_if_reach_limit is true')
|
40
45
|
end
|
41
46
|
return self unless config.enable_report?
|
42
|
-
return self if evaluate(stop_report_if) || !evaluate(
|
47
|
+
return self if evaluate(stop_report_if) || !evaluate(report_if)
|
43
48
|
return self if switch.report_is_terminated?
|
44
|
-
return self if stop_report_if_reach_limit && switch.reached_report_limit?(
|
49
|
+
return self if stop_report_if_reach_limit && switch.reached_report_limit?(report_limit_count)
|
45
50
|
|
46
51
|
Reporter.perform_later(
|
47
|
-
|
52
|
+
key: key,
|
53
|
+
limit_count: report_limit_count,
|
48
54
|
called_path: called_path,
|
49
55
|
run: run?
|
50
56
|
)
|
@@ -54,24 +60,30 @@ module CircuitSwitch
|
|
54
60
|
|
55
61
|
# @return [Boolean]
|
56
62
|
def run?
|
57
|
-
|
63
|
+
@run
|
58
64
|
end
|
59
65
|
|
60
66
|
# @return [Boolean]
|
61
67
|
def reported?
|
62
|
-
|
68
|
+
@reported
|
63
69
|
end
|
64
70
|
|
65
71
|
private
|
66
72
|
|
67
73
|
def switch
|
68
|
-
@switch
|
74
|
+
return @switch if defined? @switch
|
75
|
+
|
76
|
+
if key
|
77
|
+
@switch = CircuitSwitch.find_or_initialize_by(key: key)
|
78
|
+
else
|
79
|
+
@switch = CircuitSwitch.find_or_initialize_by(caller: called_path)
|
80
|
+
end
|
69
81
|
end
|
70
82
|
|
71
83
|
def called_path
|
72
84
|
@called_path ||= caller
|
73
|
-
.reject { |path|
|
74
|
-
.detect { |path|
|
85
|
+
.reject { |path| /(#{config.silent_paths.join('|')})/.match?(path) }
|
86
|
+
.detect { |path| /(#{config.report_paths.join('|')})/.match?(path) }
|
75
87
|
&.sub(/(#{config.strip_paths.join('|')})/, '')
|
76
88
|
&.gsub(/[`']/, '') ||
|
77
89
|
"/somewhere/in/library:in #{Date.today}"
|
@@ -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,4 +1,4 @@
|
|
1
|
-
require '
|
1
|
+
require 'active_support/core_ext/module/delegation'
|
2
2
|
|
3
3
|
module CircuitSwitch
|
4
4
|
class StacktraceModifier
|
@@ -7,7 +7,7 @@ module CircuitSwitch
|
|
7
7
|
|
8
8
|
def call(backtrace:)
|
9
9
|
backtrace
|
10
|
-
.select { |path|
|
10
|
+
.select { |path| /(#{config.allowed_backtrace_paths.join('|')})/.match?(path) }
|
11
11
|
.map { |path| path.sub(/(#{config.strip_paths.join('|')})/, '') }
|
12
12
|
.join("\n")
|
13
13
|
end
|
@@ -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,34 @@
|
|
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
|
+
config.reporter.call(notification.to_message(called_path: called_path))
|
13
31
|
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
32
|
end
|
20
33
|
end
|
21
34
|
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
|
-
# @param close_if_reach_limit [Boolean] Stop calling proc when run count reaches limit (default:
|
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: true,
|
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
|
@@ -16,6 +16,9 @@ CircuitSwitch.configure do |config|
|
|
16
16
|
# Excluded paths to report
|
17
17
|
# config.silent_paths = [CIRCUIT_SWITCH]
|
18
18
|
|
19
|
+
# Alias column name for circuit_switches.key through alias_attribute
|
20
|
+
# config.key_column_name = :key
|
21
|
+
|
19
22
|
# Notifier to notify circuit_switch's due_date come and it's time to clean code!
|
20
23
|
# Specify proc to call your report tool: like;
|
21
24
|
# config.due_date_notifier = -> (message) { Slack::Web::Client.new.chat_postMessage(channel: '#your_channel', text: message) }
|
@@ -26,10 +29,10 @@ CircuitSwitch.configure do |config|
|
|
26
29
|
|
27
30
|
# Option to contain error backtrace for report
|
28
31
|
# You don't need backtrace when you report to some bug report tool.
|
29
|
-
# You may
|
32
|
+
# You may want backtrace when reporting to a plain feed; e.g. Slack or email.
|
30
33
|
# config.with_backtrace = false
|
31
34
|
|
32
|
-
#
|
35
|
+
# Allowed backtrace paths to report
|
33
36
|
# Specify with `with_backtrace` option.
|
34
37
|
# Allowed all paths when set `[]`.
|
35
38
|
# 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.3.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-03 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
|
@@ -102,6 +116,7 @@ executables: []
|
|
102
116
|
extensions: []
|
103
117
|
extra_rdoc_files: []
|
104
118
|
files:
|
119
|
+
- ".github/workflows/main.yml"
|
105
120
|
- ".gitignore"
|
106
121
|
- CHANGELOG.md
|
107
122
|
- CODE_OF_CONDUCT.md
|
@@ -113,6 +128,7 @@ files:
|
|
113
128
|
- bin/setup
|
114
129
|
- circuit_switch.gemspec
|
115
130
|
- lib/circuit_switch.rb
|
131
|
+
- lib/circuit_switch/builder.rb
|
116
132
|
- lib/circuit_switch/configuration.rb
|
117
133
|
- lib/circuit_switch/core.rb
|
118
134
|
- lib/circuit_switch/notification.rb
|
@@ -127,7 +143,9 @@ files:
|
|
127
143
|
- lib/circuit_switch/workers/run_count_updater.rb
|
128
144
|
- lib/generators/circuit_switch/install_generator.rb
|
129
145
|
- lib/generators/circuit_switch/migration_generator.rb
|
146
|
+
- lib/generators/circuit_switch/templates/add_key.rb.erb
|
130
147
|
- lib/generators/circuit_switch/templates/initializer.rb
|
148
|
+
- lib/generators/circuit_switch/templates/make_key_unique.rb.erb
|
131
149
|
- lib/generators/circuit_switch/templates/migration.rb.erb
|
132
150
|
homepage: https://github.com/makicamel/circuit_switch
|
133
151
|
licenses:
|