circuit_switch 0.1.1 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/main.yml +27 -0
- data/CHANGELOG.md +38 -0
- data/README.md +15 -14
- data/Rakefile +9 -1
- data/circuit_switch.gemspec +3 -2
- data/lib/circuit_switch/builder.rb +66 -0
- data/lib/circuit_switch/configuration.rb +6 -0
- 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 +4 -1
- data/lib/generators/circuit_switch/templates/migration.rb.erb +1 -0
- metadata +22 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 948143d874eac4049767af92dacd5f8175ad016a951b93e95e05e3a3585eaf70
|
4
|
+
data.tar.gz: 98981a823c9fa4dd0c20259003766ecf789dd44f7ad0e7bd8983223338f5a550
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 317208a17b15dfcc29e333c217ee7320b0133a721a918d2917cd3d172615a86ffe73394e74d407454b9ff8e16fa2be702d6d22cc91467793a9260a84bae792ad
|
7
|
+
data.tar.gz: 3ec9b0893cca1eaee59e1aa40c7c3be95348b90760aff1a5fef59053e7dbeb72c627b93940e04b14d0b3c2c2d5159beb00dc13b6b6145b340871734346138428
|
@@ -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,3 +1,41 @@
|
|
1
|
+
## 0.2.2
|
2
|
+
|
3
|
+
### New features
|
4
|
+
|
5
|
+
* Add `key_column_name` to configuration for aliasing `circuit_switches.key`.
|
6
|
+
|
7
|
+
### Changes
|
8
|
+
|
9
|
+
* Declare dependent on ActiveSupport instead of implicitly dependent.
|
10
|
+
|
11
|
+
## 0.2.1
|
12
|
+
|
13
|
+
### New features
|
14
|
+
|
15
|
+
* Add `initially_closed` option to `run` and `open?`.
|
16
|
+
* Add `key` argument for easy handling for human more than caller.
|
17
|
+
To migrate, run next.
|
18
|
+
|
19
|
+
```
|
20
|
+
rails generate circuit_switch:migration circuit_switch add_key
|
21
|
+
rails db:migrate
|
22
|
+
```
|
23
|
+
|
24
|
+
### Changes
|
25
|
+
|
26
|
+
* Modify log level from warn to info when default value for `close_if_reach_limit` is used.
|
27
|
+
* Suppress warning that ivar is not initialized.
|
28
|
+
|
29
|
+
## 0.2.0
|
30
|
+
|
31
|
+
### Breaking Changes
|
32
|
+
|
33
|
+
* Modify default value of `CircuitSwitch.run` argument `close_if_reach_limit` from true to false.
|
34
|
+
|
35
|
+
## 0.1.2
|
36
|
+
|
37
|
+
* Modify `CircuitSwitch.open?` receives same arguments as `CircuitSwitch.run`
|
38
|
+
|
1
39
|
## 0.1.1
|
2
40
|
|
3
41
|
* 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
|
-
spec.metadata["changelog_uri"] = 'https://github.com/makicamel/circuit_switch/CHANGELOG.md'
|
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.
|
@@ -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
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'active_support/core_ext/module/aliasing'
|
2
|
+
|
1
3
|
module CircuitSwitch
|
2
4
|
class Configuration
|
3
5
|
CIRCUIT_SWITCH = 'circuit_switch'.freeze
|
@@ -25,6 +27,10 @@ module CircuitSwitch
|
|
25
27
|
report_if.respond_to?(:call) ? report_if.call : !!report_if
|
26
28
|
end
|
27
29
|
|
30
|
+
def key_column_name=(key)
|
31
|
+
::CircuitSwitch::CircuitSwitch.alias_attribute :key, key
|
32
|
+
end
|
33
|
+
|
28
34
|
def due_date
|
29
35
|
@due_date ||= Date.today + 10
|
30
36
|
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
|
@@ -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) }
|
@@ -29,7 +32,7 @@ CircuitSwitch.configure do |config|
|
|
29
32
|
# You may be want backtrace when report to 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]
|
@@ -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.
|
4
|
+
version: 0.2.2
|
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-31 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
|
@@ -94,14 +108,15 @@ dependencies:
|
|
94
108
|
- - ">="
|
95
109
|
- !ruby/object:Gem::Version
|
96
110
|
version: '0'
|
97
|
-
description:
|
98
|
-
|
111
|
+
description: circuit_switch is a gem for 'difficult' application. This switch helps
|
112
|
+
to make changes easier and deploy safely.
|
99
113
|
email:
|
100
114
|
- unright@gmail.com
|
101
115
|
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,6 +143,7 @@ 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
|
131
148
|
- lib/generators/circuit_switch/templates/migration.rb.erb
|
132
149
|
homepage: https://github.com/makicamel/circuit_switch
|
@@ -135,7 +152,7 @@ licenses:
|
|
135
152
|
metadata:
|
136
153
|
homepage_uri: https://github.com/makicamel/circuit_switch
|
137
154
|
source_code_uri: https://github.com/makicamel/circuit_switch
|
138
|
-
changelog_uri: https://github.com/makicamel/circuit_switch/CHANGELOG.md
|
155
|
+
changelog_uri: https://github.com/makicamel/circuit_switch/blob/main/CHANGELOG.md
|
139
156
|
post_install_message:
|
140
157
|
rdoc_options: []
|
141
158
|
require_paths:
|