circuit_switch 0.1.0 → 0.2.1
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 +31 -0
- data/README.md +15 -14
- data/Rakefile +9 -1
- data/circuit_switch.gemspec +2 -2
- data/lib/circuit_switch/builder.rb +66 -0
- data/lib/circuit_switch/configuration.rb +1 -1
- data/lib/circuit_switch/core.rb +40 -29
- data/lib/circuit_switch/notification.rb +1 -1
- data/lib/circuit_switch/orm/active_record/circuit_switch.rb +8 -1
- 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 +12 -8
- data/lib/circuit_switch/workers/run_count_updater.rb +13 -9
- data/lib/circuit_switch.rb +35 -32
- data/lib/generators/circuit_switch/migration_generator.rb +8 -1
- data/lib/generators/circuit_switch/templates/add_key.rb.erb +13 -0
- data/lib/generators/circuit_switch/templates/initializer.rb +1 -1
- data/lib/generators/circuit_switch/templates/migration.rb.erb +1 -0
- metadata +9 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9281021c31b4e885f3e8c8ca7fbd1fd83e713202950776c910f9b0951891a5c6
|
4
|
+
data.tar.gz: 8f4969657c64c2016724fabadd8d2cbddf063e6ffc3dd0298fb2e9e0b06e688a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 94cc63d4de19ffdc4cea5a5e331af21ab458f26f5333a6ceb4b84c7b3ba13edb44ebee7c0379c555d1ea7f390e8a31cb159c35c8d181cd8dec4a16cb049507ab
|
7
|
+
data.tar.gz: 2f490f1e01f4e05351cbde8ee6fe328e200c020dcbb0d83a1f627983a47c192f4c4ab8f5c3b3878bd58e7a026003d0bd79a5995044987b275b59b6d9902f478b
|
@@ -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
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
## 0.2.1
|
2
|
+
|
3
|
+
### New features
|
4
|
+
|
5
|
+
* Add `initially_closed` option to `run` and `open?`.
|
6
|
+
* Add `key` argument for easy handling for human more than caller.
|
7
|
+
To migrate, run next.
|
8
|
+
|
9
|
+
```
|
10
|
+
rails generate circuit_switch:migration add_key
|
11
|
+
rails db:migrate
|
12
|
+
```
|
13
|
+
|
14
|
+
### Changes
|
15
|
+
|
16
|
+
* Modify log level from warn to info when default value for `close_if_reach_limit` is used.
|
17
|
+
* Suppress warning that ivar is not initialized.
|
18
|
+
|
19
|
+
## 0.2.0
|
20
|
+
|
21
|
+
### Breaking Changes
|
22
|
+
|
23
|
+
* Modify default value of `CircuitSwitch.run` argument `close_if_reach_limit` from true to false.
|
24
|
+
|
25
|
+
## 0.1.2
|
26
|
+
|
27
|
+
* Modify `CircuitSwitch.open?` receives same arguments as `CircuitSwitch.run`
|
28
|
+
|
29
|
+
## 0.1.1
|
30
|
+
|
31
|
+
* Fix bug due_date is not set.
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
#
|
1
|
+
# circuit_switch
|
2
2
|
|
3
|
-
|
3
|
+
circuit_switch is a gem for 'difficult' application; for example, few tests, too many meta-programming codes, low aggregation classes and few deploys.
|
4
4
|
This switch helps make changes easier and deploy safely.
|
5
5
|
You can deploy and check with a short code like following if the change is good or not, and when a problem is found, you can undo it without releasing it.
|
6
6
|
|
@@ -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)
|
@@ -130,10 +136,11 @@ called_path: /app/services/greetings_service:21 block in validate
|
|
130
136
|
|
131
137
|
## Task
|
132
138
|
|
133
|
-
When find a problem and you want to terminate running or reporting right now, execute a task with it's caller.
|
139
|
+
When find a problem and you want to terminate running or reporting right now, execute a task with it's caller.
|
140
|
+
You can specify either key or caller.
|
134
141
|
|
135
142
|
```
|
136
|
-
rake circuit_switch:terminate_to_run[
|
143
|
+
rake circuit_switch:terminate_to_run[your_key]
|
137
144
|
rake circuit_switch:terminate_to_report[/app/services/greetings_service:21 block in validate]
|
138
145
|
```
|
139
146
|
|
@@ -153,12 +160,6 @@ By default, due_date is 10 days after today. To modify, set `due_date` to initia
|
|
153
160
|
|
154
161
|
Under development :)
|
155
162
|
|
156
|
-
## Development
|
157
|
-
|
158
|
-
After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
159
|
-
|
160
|
-
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
161
|
-
|
162
163
|
## Contributing
|
163
164
|
|
164
165
|
Bug reports and pull requests are welcome on GitHub at https://github.com/makicamel/circuit_switch. 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/makicamel/circuit_switch/blob/master/CODE_OF_CONDUCT.md).
|
data/Rakefile
CHANGED
data/circuit_switch.gemspec
CHANGED
@@ -7,14 +7,14 @@ Gem::Specification.new do |spec|
|
|
7
7
|
spec.email = ["unright@gmail.com"]
|
8
8
|
|
9
9
|
spec.summary = 'Circuit switch with report tools'
|
10
|
-
spec.description = '
|
10
|
+
spec.description = 'circuit_switch is a gem for \'difficult\' application. This switch helps to make changes easier and deploy safely.'
|
11
11
|
spec.homepage = 'https://github.com/makicamel/circuit_switch'
|
12
12
|
spec.license = "MIT"
|
13
13
|
spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
|
14
14
|
|
15
15
|
spec.metadata["homepage_uri"] = spec.homepage
|
16
16
|
spec.metadata["source_code_uri"] = 'https://github.com/makicamel/circuit_switch'
|
17
|
-
|
17
|
+
spec.metadata["changelog_uri"] = 'https://github.com/makicamel/circuit_switch/blob/main/CHANGELOG.md'
|
18
18
|
|
19
19
|
# Specify which files should be added to the gem when it is released.
|
20
20
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
@@ -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,55 @@
|
|
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
|
20
28
|
RunCountUpdater.perform_later(
|
21
|
-
|
29
|
+
key: key,
|
30
|
+
limit_count: run_limit_count,
|
22
31
|
called_path: called_path,
|
23
|
-
reported: reported
|
32
|
+
reported: reported?,
|
33
|
+
initially_closed: initially_closed
|
24
34
|
)
|
25
|
-
@run = true
|
26
35
|
self
|
27
36
|
end
|
28
37
|
|
29
|
-
def
|
30
|
-
if: true,
|
31
|
-
stop_report_if: false,
|
32
|
-
stop_report_if_reach_limit: true,
|
33
|
-
limit_count: nil
|
34
|
-
)
|
38
|
+
def execute_report
|
35
39
|
if config.reporter.nil?
|
36
40
|
raise CircuitSwitchError.new('Set config.reporter.')
|
37
41
|
end
|
38
|
-
if stop_report_if_reach_limit &&
|
42
|
+
if stop_report_if_reach_limit && report_limit_count == 0
|
39
43
|
raise CircuitSwitchError.new('Can\'t set limit_count to 0 when stop_report_if_reach_limit is true')
|
40
44
|
end
|
41
45
|
return self unless config.enable_report?
|
42
|
-
return self if evaluate(stop_report_if) || !evaluate(
|
46
|
+
return self if evaluate(stop_report_if) || !evaluate(report_if)
|
43
47
|
return self if switch.report_is_terminated?
|
44
|
-
return self if stop_report_if_reach_limit && switch.reached_report_limit?(
|
48
|
+
return self if stop_report_if_reach_limit && switch.reached_report_limit?(report_limit_count)
|
45
49
|
|
46
50
|
Reporter.perform_later(
|
47
|
-
|
51
|
+
key: key,
|
52
|
+
limit_count: report_limit_count,
|
48
53
|
called_path: called_path,
|
49
54
|
run: run?
|
50
55
|
)
|
@@ -54,24 +59,30 @@ module CircuitSwitch
|
|
54
59
|
|
55
60
|
# @return [Boolean]
|
56
61
|
def run?
|
57
|
-
|
62
|
+
@run
|
58
63
|
end
|
59
64
|
|
60
65
|
# @return [Boolean]
|
61
66
|
def reported?
|
62
|
-
|
67
|
+
@reported
|
63
68
|
end
|
64
69
|
|
65
70
|
private
|
66
71
|
|
67
72
|
def switch
|
68
|
-
@switch
|
73
|
+
return @switch if defined? @switch
|
74
|
+
|
75
|
+
if key
|
76
|
+
@switch = CircuitSwitch.find_or_initialize_by(key: key)
|
77
|
+
else
|
78
|
+
@switch = CircuitSwitch.find_or_initialize_by(caller: called_path)
|
79
|
+
end
|
69
80
|
end
|
70
81
|
|
71
82
|
def called_path
|
72
83
|
@called_path ||= caller
|
73
|
-
.reject { |path|
|
74
|
-
.detect { |path|
|
84
|
+
.reject { |path| /(#{config.silent_paths.join('|')})/.match?(path) }
|
85
|
+
.detect { |path| /(#{config.report_paths.join('|')})/.match?(path) }
|
75
86
|
&.sub(/(#{config.strip_paths.join('|')})/, '')
|
76
87
|
&.gsub(/[`']/, '') ||
|
77
88
|
"/somewhere/in/library:in #{Date.today}"
|
@@ -1,5 +1,11 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
|
1
3
|
module CircuitSwitch
|
2
4
|
class CircuitSwitch < ::ActiveRecord::Base
|
5
|
+
after_initialize do |switch|
|
6
|
+
switch.key ||= switch.caller
|
7
|
+
end
|
8
|
+
|
3
9
|
def assign(run_limit_count: nil, report_limit_count: nil)
|
4
10
|
self.run_limit_count = run_limit_count if run_limit_count
|
5
11
|
self.report_limit_count = report_limit_count if report_limit_count
|
@@ -31,7 +37,8 @@ module CircuitSwitch
|
|
31
37
|
end
|
32
38
|
|
33
39
|
def message
|
34
|
-
|
40
|
+
process = key == caller ? 'Watching process' : "Process for '#{key}'"
|
41
|
+
"#{process} is called for #{report_count}th. Report until for #{report_limit_count}th."
|
35
42
|
end
|
36
43
|
|
37
44
|
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,16 +1,20 @@
|
|
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
|
-
CircuitSwitch.find_or_initialize_by(caller: called_path)
|
8
|
+
def perform(key:, limit_count:, called_path:, run:)
|
9
|
+
# Wait for RunCountUpdater saves circuit_switch
|
10
|
+
sleep(3) if run
|
11
|
+
|
12
|
+
circuit_switch = key ? CircuitSwitch.find_by(key: key) : CircuitSwitch.find_by(caller: called_path)
|
13
|
+
if run && circuit_switch.nil?
|
14
|
+
raise ActiveRecord::RecordNotFound.new('Couldn\'t find CircuitSwitch::CircuitSwitch')
|
13
15
|
end
|
16
|
+
|
17
|
+
circuit_switch ||= CircuitSwitch.new(key: key, caller: called_path)
|
14
18
|
circuit_switch.due_date ||= config.due_date
|
15
19
|
circuit_switch.assign(report_limit_count: limit_count).increment_report_count
|
16
20
|
raise CalledNotification.new(circuit_switch.message)
|
@@ -1,16 +1,20 @@
|
|
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
|
-
|
13
|
-
|
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
|
+
circuit_switch = key ? CircuitSwitch.find_by(key: key) : CircuitSwitch.find_by(caller: called_path)
|
13
|
+
if reported && circuit_switch.nil?
|
14
|
+
raise ActiveRecord::RecordNotFound.new('Couldn\'t find CircuitSwitch::CircuitSwitch')
|
15
|
+
end
|
16
|
+
|
17
|
+
circuit_switch ||= CircuitSwitch.new(key: key, caller: called_path, run_is_terminated: initially_closed)
|
14
18
|
circuit_switch.due_date ||= config.due_date
|
15
19
|
circuit_switch.assign(run_limit_count: limit_count).increment_run_count
|
16
20
|
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,63 +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)
|
62
|
+
# @param close_if [Boolean, Proc] `CircuitSwitch.run` is runnable when `close_if` is falsy (default: false)
|
63
|
+
# @param close_if_reach_limit [Boolean] `CircuitSwitch.run` is NOT runnable when run count reaches limit (default: true)
|
68
64
|
# @param limit_count [Integer] Limit count. Use `run_limit_count` default value if it's nil. Can't be set 0 (default: nil)
|
69
|
-
|
65
|
+
# @param initially_closed [Boolean] Create switch with terminated mode (default: false)
|
66
|
+
# @return [Boolean]
|
67
|
+
def open?(key: nil, if: nil, close_if: nil, close_if_reach_limit: nil, limit_count: nil, initially_closed: nil)
|
70
68
|
if block_given?
|
71
69
|
raise ArgumentError.new('CircuitSwitch.open doesn\'t receive block. Use CircuitSwitch.run if you want to pass block.')
|
72
70
|
end
|
73
71
|
|
74
|
-
|
72
|
+
arguments = {
|
73
|
+
key: key,
|
75
74
|
if: binding.local_variable_get(:if),
|
76
|
-
|
77
|
-
|
75
|
+
close_if: close_if,
|
76
|
+
close_if_reach_limit: close_if_reach_limit,
|
77
|
+
limit_count: limit_count,
|
78
|
+
initially_closed: initially_closed,
|
79
|
+
}.select { |_, v| v }
|
80
|
+
Builder.new.run(**arguments) {}.run?
|
78
81
|
end
|
79
82
|
end
|
80
83
|
end
|
@@ -4,9 +4,16 @@ 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. By default to create.',
|
9
|
+
banner: 'create or add_key'
|
7
10
|
|
8
11
|
def generate_migration
|
9
|
-
|
12
|
+
if migration_type == ['add_key']
|
13
|
+
migration_template 'add_key.rb.erb', 'db/migrate/add_key_to_circuit_switches.rb', migration_version: migration_version
|
14
|
+
else
|
15
|
+
migration_template 'migration.rb.erb', 'db/migrate/create_circuit_switches.rb', migration_version: migration_version
|
16
|
+
end
|
10
17
|
end
|
11
18
|
|
12
19
|
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
|
@@ -29,7 +29,7 @@ CircuitSwitch.configure do |config|
|
|
29
29
|
# You may be want backtrace when report to plain feed; e.g. Slack or email.
|
30
30
|
# config.with_backtrace = false
|
31
31
|
|
32
|
-
#
|
32
|
+
# Allowed backtrace paths to report
|
33
33
|
# Specify with `with_backtrace` option.
|
34
34
|
# Allowed all paths when set `[]`.
|
35
35
|
# config.allowed_backtrace_paths = [Dir.pwd]
|
@@ -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, index: true
|
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
|
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.1
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- makicamel
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-10-
|
11
|
+
date: 2021-10-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activejob
|
@@ -94,15 +94,17 @@ dependencies:
|
|
94
94
|
- - ">="
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0'
|
97
|
-
description:
|
98
|
-
|
97
|
+
description: circuit_switch is a gem for 'difficult' application. This switch helps
|
98
|
+
to make changes easier and deploy safely.
|
99
99
|
email:
|
100
100
|
- unright@gmail.com
|
101
101
|
executables: []
|
102
102
|
extensions: []
|
103
103
|
extra_rdoc_files: []
|
104
104
|
files:
|
105
|
+
- ".github/workflows/main.yml"
|
105
106
|
- ".gitignore"
|
107
|
+
- CHANGELOG.md
|
106
108
|
- CODE_OF_CONDUCT.md
|
107
109
|
- Gemfile
|
108
110
|
- LICENSE.txt
|
@@ -112,6 +114,7 @@ files:
|
|
112
114
|
- bin/setup
|
113
115
|
- circuit_switch.gemspec
|
114
116
|
- lib/circuit_switch.rb
|
117
|
+
- lib/circuit_switch/builder.rb
|
115
118
|
- lib/circuit_switch/configuration.rb
|
116
119
|
- lib/circuit_switch/core.rb
|
117
120
|
- lib/circuit_switch/notification.rb
|
@@ -126,6 +129,7 @@ files:
|
|
126
129
|
- lib/circuit_switch/workers/run_count_updater.rb
|
127
130
|
- lib/generators/circuit_switch/install_generator.rb
|
128
131
|
- lib/generators/circuit_switch/migration_generator.rb
|
132
|
+
- lib/generators/circuit_switch/templates/add_key.rb.erb
|
129
133
|
- lib/generators/circuit_switch/templates/initializer.rb
|
130
134
|
- lib/generators/circuit_switch/templates/migration.rb.erb
|
131
135
|
homepage: https://github.com/makicamel/circuit_switch
|
@@ -134,6 +138,7 @@ licenses:
|
|
134
138
|
metadata:
|
135
139
|
homepage_uri: https://github.com/makicamel/circuit_switch
|
136
140
|
source_code_uri: https://github.com/makicamel/circuit_switch
|
141
|
+
changelog_uri: https://github.com/makicamel/circuit_switch/blob/main/CHANGELOG.md
|
137
142
|
post_install_message:
|
138
143
|
rdoc_options: []
|
139
144
|
require_paths:
|