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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8e327f0f981b9690cd6115067a3ede6d399d3ea25fb905da56629c58954b7db4
4
- data.tar.gz: 75b1a01d86987a360a0e898180d382d56358efe14f681156ed3d4f60998bdfea
3
+ metadata.gz: 9281021c31b4e885f3e8c8ca7fbd1fd83e713202950776c910f9b0951891a5c6
4
+ data.tar.gz: 8f4969657c64c2016724fabadd8d2cbddf063e6ffc3dd0298fb2e9e0b06e688a
5
5
  SHA512:
6
- metadata.gz: 403ae1fd2a6e17d2834b07ce745ecf5787342bb6177544ac15c9e53d09d4b1782dbc50311e78519b0298f8a644af2d4b9ff14d4eb976ea90418c0a8c008bd907
7
- data.tar.gz: fa0a9770084140cdc794b39b15d60f5694a8f1cc98b8146e3ee0a7a6d7eb9c08117206208f3b019ec39c18ce11bfeaaa158fcd9c2d5e9ee0fa9d37d07f2c9b49
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
- # CircuitSwitch
1
+ # circuit_switch
2
2
 
3
- CircuitSwitch is a gem for 'difficult' application; for example, few tests, too many meta-programming codes, low aggregation classes and few deploys.
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 closed when reached the specified count. The default count is 10. To change this default value, modify `circuit_switches.run_limit_count` default value in the migration file.
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: true)
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` doesn't receive proc.
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[/app/services/greetings_service:21 block in validate]
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
@@ -1,2 +1,10 @@
1
1
  require "bundler/gem_tasks"
2
- task :default => :spec
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList["test/**/*_test.rb"]
8
+ end
9
+
10
+ task :default => :test
@@ -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 = 'Circuit switch to help changing source code in safety and easy with report tools'
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"] = "TODO: Put your gem's CHANGELOG.md URL here."
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
@@ -26,7 +26,7 @@ module CircuitSwitch
26
26
  end
27
27
 
28
28
  def due_date
29
- @due_date = Date.today + 10
29
+ @due_date ||= Date.today + 10
30
30
  end
31
31
 
32
32
  def with_backtrace
@@ -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 run(
6
- if: true,
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
- return self if evaluate(close_if) || !evaluate(binding.local_variable_get(:if))
16
- return self if close_if_reach_limit && switch.reached_run_limit?(limit_count)
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
- yield
24
+ unless switch.new_record? && initially_closed
25
+ yield
26
+ @run = true
27
+ end
20
28
  RunCountUpdater.perform_later(
21
- limit_count: limit_count,
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 report(
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 && limit_count == 0
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(binding.local_variable_get(:if))
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?(limit_count)
48
+ return self if stop_report_if_reach_limit && switch.reached_report_limit?(report_limit_count)
45
49
 
46
50
  Reporter.perform_later(
47
- limit_count: limit_count,
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
- !!@run
62
+ @run
58
63
  end
59
64
 
60
65
  # @return [Boolean]
61
66
  def reported?
62
- !!@reported
67
+ @reported
63
68
  end
64
69
 
65
70
  private
66
71
 
67
72
  def switch
68
- @switch ||= CircuitSwitch.find_or_initialize_by(caller: called_path)
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| path.match?(/(#{config.silent_paths.join('|')})/) }
74
- .detect { |path| path.match?(/(#{config.report_paths.join('|')})/) }
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,4 +1,4 @@
1
- require 'circuit_switch/stacktrace_modifier'
1
+ require_relative 'stacktrace_modifier'
2
2
 
3
3
  module CircuitSwitch
4
4
  class CircuitSwitchError < RuntimeError
@@ -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
- "Watching process is called for #{report_count}th. Report until for #{report_limit_count}th."
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 'circuit_switch/configuration.rb'
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| path.match?(/(#{config.allowed_backtrace_paths.join('|')})/) }
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, ['caller'] => :environment do |_, arg|
4
- called_path = arg[:caller]
5
- puts "Start to update run_is_terminated of circuit_switch for '#{called_path}' to true."
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: called_path)
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 '#{called_path}' to true."
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, ['caller'] => :environment do |_, arg|
17
- called_path = arg[:caller]
18
- puts "Start to update report_is_terminated of circuit_switch for '#{called_path}' to true."
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: called_path)
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 '#{called_path}' to true."
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, ['caller'] => :environment do |_, arg|
30
- called_path = arg[:caller]
31
- puts "Start to delete circuit_switch for '#{called_path}'."
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: called_path)
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 '#{called_path}'."
38
+ puts "Successfully deleted circuit_switch for '#{key_or_caller}'."
39
39
  end
40
40
  end
@@ -1,3 +1,3 @@
1
1
  module CircuitSwitch
2
- VERSION = "0.1.0"
2
+ VERSION = '0.2.1'
3
3
  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}' , created_at: #{switch.created_at}" }.join("\n")
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
- # Wait for RunCountUpdater saves circuit_switch
9
- sleep(3)
10
- CircuitSwitch.find_by!(caller: called_path)
11
- else
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
- if reported
8
- # Wait for Reporter saves circuit_switch
9
- sleep(3)
10
- CircuitSwitch.find_by!(caller: called_path)
11
- else
12
- CircuitSwitch.find_or_initialize_by(caller: called_path)
13
- end
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
@@ -1,12 +1,9 @@
1
- require "circuit_switch/configuration.rb"
2
- require "circuit_switch/core"
3
- require "circuit_switch/notification"
4
- require "circuit_switch/orm/active_record/circuit_switch"
5
- require "circuit_switch/railtie" if defined?(Rails::Railtie)
6
- require "circuit_switch/version"
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: true)
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
- if: true,
29
- close_if: false,
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
- &block
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
- Core.new.report(
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
- def open?(if: true, limit_count: nil)
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
- Core.new.run(
72
+ arguments = {
73
+ key: key,
75
74
  if: binding.local_variable_get(:if),
76
- limit_count: limit_count
77
- ) {}.run?
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
- migration_template 'migration.rb.erb', 'db/migrate/create_circuit_switches.rb', migration_version: migration_version
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
- # Allowd backtrace paths to report
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.0
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-04 00:00:00.000000000 Z
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: Circuit switch to help changing source code in safety and easy with report
98
- tools
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: