procon_bypass_man 0.2.2 → 0.2.3

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.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +6 -6
  3. data/.rubocop.yml +4 -0
  4. data/.ruby-version +1 -1
  5. data/CHANGELOG.md +5 -0
  6. data/Gemfile.lock +1 -1
  7. data/README.md +15 -6
  8. data/Steepfile +0 -1
  9. data/docs/getting_started.md +48 -20
  10. data/docs/setup_raspi_by_mitamae.md +44 -2
  11. data/lib/procon_bypass_man/background/job_performer.rb +1 -2
  12. data/lib/procon_bypass_man/background/job_queue.rb +50 -0
  13. data/lib/procon_bypass_man/background/jobs/concerns/has_external_api_setting.rb +2 -2
  14. data/lib/procon_bypass_man/background/jobs/concerns/job_performable.rb +2 -2
  15. data/lib/procon_bypass_man/background/jobs/post_completed_remote_macro_job.rb +1 -1
  16. data/lib/procon_bypass_man/background/jobs/report_boot_job.rb +1 -1
  17. data/lib/procon_bypass_man/background/jobs/report_completed_upgrade_pbm_job.rb +1 -1
  18. data/lib/procon_bypass_man/background/jobs/report_error_job.rb +1 -1
  19. data/lib/procon_bypass_man/background/jobs/report_error_reload_config_job.rb +1 -1
  20. data/lib/procon_bypass_man/background/jobs/report_load_config_job.rb +1 -1
  21. data/lib/procon_bypass_man/background/jobs/report_procon_performance_measurements_job.rb +43 -0
  22. data/lib/procon_bypass_man/background/jobs/report_reload_config_job.rb +1 -1
  23. data/lib/procon_bypass_man/background/jobs/report_start_reboot_job.rb +1 -1
  24. data/lib/procon_bypass_man/background/jobs/sync_device_stats_job.rb +1 -1
  25. data/lib/procon_bypass_man/background.rb +2 -3
  26. data/lib/procon_bypass_man/bypass/bypass_command.rb +6 -15
  27. data/lib/procon_bypass_man/bypass/bypass_value.rb +6 -0
  28. data/lib/procon_bypass_man/bypass/procon_to_switch.rb +107 -0
  29. data/lib/procon_bypass_man/bypass/switch_to_procon.rb +64 -0
  30. data/lib/procon_bypass_man/bypass.rb +5 -110
  31. data/lib/procon_bypass_man/configuration.rb +15 -39
  32. data/lib/procon_bypass_man/device_connection/procon_setting_overrider.rb +12 -3
  33. data/lib/procon_bypass_man/procon/macro.rb +1 -1
  34. data/lib/procon_bypass_man/procon/performance_measurement/last_bypass_at.rb +17 -0
  35. data/lib/procon_bypass_man/procon/performance_measurement/measurement_collection.rb +9 -0
  36. data/lib/procon_bypass_man/procon/performance_measurement/measurements_summarizer.rb +84 -0
  37. data/lib/procon_bypass_man/procon/performance_measurement/procon_performance_span_transfer_job.rb +8 -0
  38. data/lib/procon_bypass_man/procon/performance_measurement/queue_over_process.rb +38 -0
  39. data/lib/procon_bypass_man/procon/performance_measurement/span_queue.rb +42 -0
  40. data/lib/procon_bypass_man/procon/performance_measurement/span_transfer_buffer.rb +39 -0
  41. data/lib/procon_bypass_man/procon/performance_measurement.rb +103 -0
  42. data/lib/procon_bypass_man/procon.rb +2 -1
  43. data/lib/procon_bypass_man/procon_display/bypass_hook.rb +4 -3
  44. data/lib/procon_bypass_man/remote_macro/queue_over_process.rb +26 -44
  45. data/lib/procon_bypass_man/remote_macro/remote_macro_object.rb +22 -24
  46. data/lib/procon_bypass_man/remote_macro/remote_macro_receiver.rb +1 -1
  47. data/lib/procon_bypass_man/remote_macro/remote_macro_sender.rb +1 -1
  48. data/lib/procon_bypass_man/remote_macro/task.rb +1 -5
  49. data/lib/procon_bypass_man/remote_macro/task_queue.rb +6 -10
  50. data/lib/procon_bypass_man/remote_pbm_action/commands/update_remote_pbm_action_status_command.rb +1 -1
  51. data/lib/procon_bypass_man/runner.rb +4 -10
  52. data/lib/procon_bypass_man/scheduler.rb +15 -6
  53. data/lib/procon_bypass_man/support/callbacks.rb +8 -4
  54. data/lib/procon_bypass_man/support/can_over_process.rb +60 -0
  55. data/lib/procon_bypass_man/support/gc.rb +8 -0
  56. data/lib/procon_bypass_man/support/http_client.rb +9 -6
  57. data/lib/procon_bypass_man/support/load_agv.rb +20 -0
  58. data/lib/procon_bypass_man/support/procon_performance_http_client.rb +7 -0
  59. data/lib/procon_bypass_man/support/retryable.rb +16 -0
  60. data/lib/procon_bypass_man/support/signal_handler.rb +1 -1
  61. data/lib/procon_bypass_man/version.rb +1 -1
  62. data/lib/procon_bypass_man/websocket/client.rb +2 -2
  63. data/lib/procon_bypass_man/worker.rb +32 -0
  64. data/lib/procon_bypass_man.rb +40 -10
  65. data/project_template/app.rb +4 -6
  66. data/project_template/app.rb.erb +4 -6
  67. data/sig/main.rbs +10 -52
  68. metadata +21 -8
  69. data/lib/procon_bypass_man/background/job_runner.rb +0 -45
  70. data/lib/procon_bypass_man/background/jobs/concerns/has_internal_api_setting.rb +0 -5
  71. data/lib/procon_bypass_man/background/jobs/report_pressed_buttons_job.rb +0 -15
  72. data/lib/procon_bypass_man/bypass/usb_hid_logger.rb +0 -43
  73. data/lib/procon_bypass_man/io_monitor.rb +0 -108
  74. data/lib/procon_bypass_man/support/server_pool.rb +0 -46
@@ -0,0 +1,42 @@
1
+ class ProconBypassMan::Procon::PerformanceMeasurement::SpanQueue
2
+ def initialize
3
+ @current_table = {} # 1つのスレッドからしか触らないのでlockはいらない
4
+ @measurement_collection_list = [] # main threadとjob worker threadから触るのでlockが必要
5
+ end
6
+
7
+ # @param [Array<PerformanceSpan>] spans
8
+ # bypassプロセスから呼ばれる. 実際に実行を行なっているのはmasterプロセス
9
+ def push(new_spans)
10
+ current_key = generate_bucket_key
11
+
12
+ if @current_table[current_key].nil?
13
+ if not @current_table.empty?
14
+ timestamp_key = @current_table.keys.first
15
+ spans = @current_table.values.first
16
+ # 本当ならmutexでlockする必要があるけど、正確性はいらないのでパフォーマンスを上げるためにlockしない
17
+ @measurement_collection_list.push(
18
+ ProconBypassMan::Procon::PerformanceMeasurement::MeasurementCollection.new(timestamp_key: timestamp_key, spans: spans)
19
+ )
20
+ end
21
+
22
+ @current_table = {}
23
+ @current_table[current_key] = []
24
+ @current_table[current_key].concat(new_spans)
25
+ else
26
+ @current_table[current_key].concat(new_spans)
27
+ end
28
+ end
29
+
30
+ # job workerから呼ばれる
31
+ # @return [ProconBypassMan::Procon::PerformanceMeasurement::MeasurementCollection]
32
+ def pop
33
+ @measurement_collection_list.pop
34
+ end
35
+
36
+ private
37
+
38
+ # 1分単位で次の値になる
39
+ def generate_bucket_key
40
+ Time.new.strftime("%Y-%m-%d %H:%M:00%:z")
41
+ end
42
+ end
@@ -0,0 +1,39 @@
1
+ class ProconBypassMan::Procon::PerformanceMeasurement::SpanTransferBuffer
2
+ include Singleton
3
+
4
+ def initialize
5
+ @buff = []
6
+ end
7
+
8
+ # @param [Span]
9
+ # @return [void]
10
+ def push_and_run_block_if_buffer_over(value, &block)
11
+ push(value)
12
+ return unless buffer_over?
13
+
14
+ block.call(spans)
15
+ clear
16
+ end
17
+
18
+ private
19
+
20
+ def spans
21
+ @buff
22
+ end
23
+
24
+ def clear
25
+ @buff.clear
26
+ end
27
+
28
+ def push(value)
29
+ @buff << value
30
+ end
31
+
32
+ def buffer_over?
33
+ @buff.length > max_buffer
34
+ end
35
+
36
+ def max_buffer
37
+ 200
38
+ end
39
+ end
@@ -0,0 +1,103 @@
1
+ module ProconBypassMan::Procon::PerformanceMeasurement; end
2
+
3
+ require 'benchmark'
4
+ require 'procon_bypass_man/procon/performance_measurement/measurements_summarizer'
5
+ require 'procon_bypass_man/procon/performance_measurement/span_queue'
6
+ require 'procon_bypass_man/procon/performance_measurement/procon_performance_span_transfer_job'
7
+ require 'procon_bypass_man/procon/performance_measurement/span_transfer_buffer'
8
+ require 'procon_bypass_man/procon/performance_measurement/measurement_collection'
9
+ require 'procon_bypass_man/procon/performance_measurement/queue_over_process'
10
+ require 'procon_bypass_man/procon/performance_measurement/last_bypass_at'
11
+
12
+ module ProconBypassMan::Procon::PerformanceMeasurement
13
+ class PerformanceSpan
14
+ attr_accessor :time_taken, :succeed, :interval_from_previous_succeed, :gc_count, :gc_time
15
+ attr_reader :write_error_count, :read_error_count, :write_time, :read_time
16
+
17
+ def initialize
18
+ @write_error_count = 0
19
+ @read_error_count = 0
20
+ @time_taken = 0.0
21
+ @succeed = nil
22
+ @interval_from_previous_succeed = nil
23
+ @custom_metric = {}
24
+ @write_time = 0.0
25
+ @read_time = 0.0
26
+ @gc_time = 0.0
27
+ end
28
+
29
+ def record_read_error
30
+ @read_error_count += 1
31
+ end
32
+
33
+ def record_write_error
34
+ @write_error_count += 1
35
+ end
36
+
37
+ def record_write_time(&block)
38
+ result = nil
39
+ @write_time = Benchmark.realtime { result = block.call }
40
+ return result
41
+ end
42
+
43
+ def record_read_time(&block)
44
+ @read_time = Benchmark.realtime { block.call }
45
+ end
46
+ end
47
+
48
+ # measureをして、measureの結果をためる
49
+ # @return [Boolean] 成功したか. テスト時に戻り値を使いたい
50
+ def self.measure(&bypass_process_block)
51
+ unless ProconBypassMan.config.enable_procon_performance_measurement?
52
+ bypass_process_block.call(PerformanceSpan.new)
53
+ return
54
+ end
55
+
56
+ if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.1.0")
57
+ snapshot_gc_time = GC.stat(:time) / 1000.0
58
+ end
59
+ snapshot_gc_count = GC.count
60
+ span = PerformanceSpan.new
61
+
62
+ span.time_taken = Benchmark.realtime {
63
+ span.succeed = bypass_process_block.call(span)
64
+ }.floor(3)
65
+
66
+ if span.succeed
67
+ ProconBypassMan::Procon::PerformanceMeasurement::LastBypassAt.touch do |interval_from_previous_succeed|
68
+ span.interval_from_previous_succeed = interval_from_previous_succeed.floor(3)
69
+ end
70
+ end
71
+
72
+ (GC.count - snapshot_gc_count).tap do |increased_gc_count|
73
+ span.gc_count = increased_gc_count
74
+ end
75
+
76
+ if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.1.0")
77
+ ((GC.stat(:time) / 1000.0) - snapshot_gc_time).tap do |increased_time|
78
+ span.gc_time = increased_time
79
+ end
80
+ end
81
+
82
+ ProconBypassMan::GC.stop_gc_in do
83
+ # measureするたびにperform_asyncしているとjob queueが詰まるのでbufferingしている
84
+ ProconBypassMan::Procon::PerformanceMeasurement::SpanTransferBuffer.instance.push_and_run_block_if_buffer_over(span) do |spans|
85
+ ProconBypassMan::ProconPerformanceSpanTransferJob.perform_async(spans.dup)
86
+ end
87
+ end
88
+ return span.succeed
89
+ end
90
+
91
+ # @return [MeasurementCollection, NilClass]
92
+ # bypassしているプロセスから呼ばれる
93
+ def self.pop_measurement_collection
94
+ ProconBypassMan::Procon::PerformanceMeasurement::QueueOverProcess.pop
95
+ end
96
+
97
+ # @param [MeasurementCollection] spans
98
+ # @return [ProconBypassMan::Procon::PerformanceMeasurement::MeasurementsSummarizer::PerformanceMetric]
99
+ # jobから呼ばれる予定
100
+ def self.summarize(spans: )
101
+ ProconBypassMan::Procon::PerformanceMeasurement::MeasurementsSummarizer.new(spans: spans).summarize
102
+ end
103
+ end
@@ -7,8 +7,9 @@ class ProconBypassMan::Procon
7
7
  require "procon_bypass_man/procon/value_objects/rumble_binary"
8
8
  require "procon_bypass_man/procon/value_objects/binary"
9
9
  require "procon_bypass_man/procon/value_objects/bypass_mode"
10
-
11
10
  require "procon_bypass_man/procon/consts"
11
+ require "procon_bypass_man/procon/performance_measurement"
12
+ require "procon_bypass_man/procon/performance_measurement/queue_over_process"
12
13
  require "procon_bypass_man/procon/mode_registry"
13
14
  require "procon_bypass_man/procon/macro"
14
15
  require "procon_bypass_man/procon/macro_registry"
@@ -1,11 +1,12 @@
1
1
  module ProconBypassMan::ProconDisplay::BypassHook
2
2
  include ProconBypassMan::Callbacks
3
3
 
4
- define_callbacks :send_procon_to_gadget
4
+ define_callbacks :run
5
5
 
6
- set_callback :send_procon_to_gadget, :after, :write_procon_display_Status
6
+ set_callback :run, :after, :write_procon_display_status
7
7
 
8
- def write_procon_display_Status
8
+ def write_procon_display_status
9
+ return unless bypass_value.binary
9
10
  ProconBypassMan::ProconDisplay::Status.instance.current = bypass_value.binary.to_procon_reader.to_hash.dup
10
11
  end
11
12
  end
@@ -1,62 +1,44 @@
1
- class ProconBypassMan::QueueOverProcess
2
- attr_reader :drb
3
-
4
- @@drb_server = nil
5
- @@drb_server_thread = nil
6
-
7
- def self.start!
8
- return unless ProconBypassMan.config.enable_remote_macro?
9
- require 'drb/drb'
10
-
11
- FileUtils.rm_rf(file_path) if File.exist?(file_path)
12
- begin
13
- @@drb_server = DRb.start_service(url, Queue.new, safe_level: 1)
14
- rescue Errno::EADDRINUSE => e
15
- ProconBypassMan.logger.error e
16
- raise
17
- end
18
-
19
- @@drb_server_thread =
20
- Thread.new do
21
- DRb.thread.join
22
- end
23
- end
1
+ class ProconBypassMan::RemoteMacro::QueueOverProcess
2
+ extend ProconBypassMan::CanOverProcess
24
3
 
25
- def self.shutdown
26
- if @@drb_server
27
- @@drb_server_thread.kill
28
- @@drb_server.stop_service
29
- end
30
- end
4
+ include Singleton
31
5
 
32
- def self.push(value)
33
- return unless ProconBypassMan.config.enable_remote_macro?
6
+ attr_reader :distributed_queue
34
7
 
35
- drb.push(value)
8
+ # @override
9
+ def self.enable?
10
+ ProconBypassMan.config.enable_remote_macro?
36
11
  end
37
12
 
38
- def self.pop
39
- return unless ProconBypassMan.config.enable_remote_macro?
13
+ # @override
14
+ def self.distributed_class
15
+ Queue
16
+ end
40
17
 
41
- drb.pop
18
+ # @override
19
+ def self.socket_file_path
20
+ "/tmp/procon_bypass_man_remote_macro_queue".freeze
42
21
  end
43
22
 
44
- def self.drb
45
- return unless ProconBypassMan.config.enable_remote_macro?
23
+ def self.push(value)
24
+ return unless enable?
46
25
 
47
- @@drb ||= new.drb
26
+ instance.distributed_queue.push(value)
48
27
  end
49
28
 
50
- PROTOCOL = "drbunix"
51
- def self.url
52
- "#{PROTOCOL}:/tmp/procon_bypass_man_queue"
29
+ def self.pop
30
+ return unless enable?
31
+
32
+ instance.distributed_queue.pop
53
33
  end
54
34
 
55
- def self.file_path
56
- url.gsub("#{PROTOCOL}:", "")
35
+ def self.clear
36
+ return unless enable?
37
+
38
+ instance.distributed_queue.clear
57
39
  end
58
40
 
59
41
  def initialize
60
- @drb = DRbObject.new_with_uri(self.class.url)
42
+ @distributed_queue = DRbObject.new_with_uri(self.class.socket_path)
61
43
  end
62
44
  end
@@ -1,30 +1,28 @@
1
- module ProconBypassMan
2
- class RemoteMacroObject
3
- # valueobjectがvalidatorの責務も持っている. 今度分離する
4
- class ValidationError < StandardError; end
5
- class MustBeNotNilError < ValidationError; end
6
- class NonSupportAction < ValidationError; end
1
+ class ProconBypassMan::RemoteMacro::RemoteMacroObject
2
+ # valueobjectがvalidatorの責務も持っている. 今度分離する
3
+ class ValidationError < StandardError; end
4
+ class MustBeNotNilError < ValidationError; end
5
+ class NonSupportAction < ValidationError; end
7
6
 
8
- attr_accessor :name, :uuid, :steps
7
+ attr_accessor :name, :uuid, :steps
9
8
 
10
- # @param [String] name
11
- # @param [String] uuid
12
- # @param [Array] steps
13
- def initialize(name: , uuid:, steps: )
14
- @name = name
15
- @uuid = uuid
16
- @steps = steps
17
- freeze
18
- end
9
+ # @param [String] name
10
+ # @param [String] uuid
11
+ # @param [Array] steps
12
+ def initialize(name: , uuid:, steps: )
13
+ @name = name
14
+ @uuid = uuid
15
+ @steps = steps
16
+ freeze
17
+ end
19
18
 
20
- # @raise [MustBeNotNilError]
21
- # @raise [NonSupportAction]
22
- # @return [void]
23
- def validate!
24
- self.uuid or raise MustBeNotNilError, "uuidは値が必須です"
25
- unless self.steps.is_a?(Array)
26
- raise ValidationError, "stepsは配列です"
27
- end
19
+ # @raise [MustBeNotNilError]
20
+ # @raise [NonSupportAction]
21
+ # @return [void]
22
+ def validate!
23
+ self.uuid or raise MustBeNotNilError, "uuidは値が必須です"
24
+ unless self.steps.is_a?(Array)
25
+ raise ValidationError, "stepsは配列です"
28
26
  end
29
27
  end
30
28
  end
@@ -15,7 +15,7 @@ class ProconBypassMan::RemoteMacroReceiver
15
15
  end
16
16
 
17
17
  def self.run
18
- while(task = ProconBypassMan::QueueOverProcess.pop)
18
+ while(task = ProconBypassMan::RemoteMacro::QueueOverProcess.pop)
19
19
  receive(task)
20
20
  end
21
21
  shutdown
@@ -1,7 +1,7 @@
1
1
  class ProconBypassMan::RemoteMacroSender
2
2
  def self.execute(name: , uuid: , steps: )
3
3
  ProconBypassMan.logger.info "[remote macro][sender] name: #{name}, uuid: #{uuid}, steps: #{steps}"
4
- ProconBypassMan::QueueOverProcess.push(
4
+ ProconBypassMan::RemoteMacro::QueueOverProcess.push(
5
5
  ProconBypassMan::RemoteMacro::Task.new(name, uuid, steps)
6
6
  )
7
7
  end
@@ -1,6 +1,2 @@
1
- module ProconBypassMan
2
- module RemoteMacro
3
- class Task < Struct.new(:name, :uuid, :steps)
4
- end
5
- end
1
+ class ProconBypassMan::RemoteMacro::Task < ::Struct.new(:name, :uuid, :steps)
6
2
  end
@@ -1,13 +1,9 @@
1
- module ProconBypassMan
2
- module RemoteMacro
3
- class TaskQueue < ::Queue
4
- def present?
5
- not empty?
6
- end
1
+ class ProconBypassMan::RemoteMacro::TaskQueue < ::Queue
2
+ def present?
3
+ not empty?
4
+ end
7
5
 
8
- def non_blocking_shift
9
- present? && shift
10
- end
11
- end
6
+ def non_blocking_shift
7
+ present? && shift
12
8
  end
13
9
  end
@@ -10,7 +10,7 @@ module ProconBypassMan
10
10
  def execute(to_status: )
11
11
  ProconBypassMan::UpdateRemotePbmActionStatusHttpClient.new(
12
12
  path: path,
13
- server_pool: ProconBypassMan.config.server_pool,
13
+ server: ProconBypassMan.config.api_server,
14
14
  ).put(to_status: to_status)
15
15
  end
16
16
 
@@ -1,8 +1,4 @@
1
- require_relative "io_monitor"
2
-
3
1
  class ProconBypassMan::Runner
4
- class InterruptForRestart < StandardError; end
5
-
6
2
  include ProconBypassMan::SignalHandler
7
3
 
8
4
  def initialize(gadget: , procon: )
@@ -24,14 +20,12 @@ class ProconBypassMan::Runner
24
20
 
25
21
  loop do
26
22
  # NOTE メインプロセスではThreadをいくつか起動しているので念のためパフォーマンスを優先するためにforkしていく
27
- child_pid = Kernel.fork {
23
+ child_pid = Kernel.fork do
28
24
  $will_terminate_token = false
29
- DRb.start_service if defined?(DRb)
30
- ProconBypassMan::RemoteMacroReceiver.start!
31
- ProconBypassMan::ProconDisplay::Server.start!
25
+ ProconBypassMan.after_fork_on_bypass_process
32
26
  ProconBypassMan::BypassCommand.new(gadget: @gadget, procon: @procon).execute # ここでblockingする
33
27
  next
34
- }
28
+ end
35
29
 
36
30
  begin
37
31
  # TODO 子プロセスが消滅した時に、メインプロセスは生き続けてしまい、何もできなくなる問題がある
@@ -39,7 +33,7 @@ class ProconBypassMan::Runner
39
33
  signal = readable_io.first[0].gets.strip
40
34
  handle_signal(signal)
41
35
  end
42
- rescue InterruptForRestart
36
+ rescue ProconBypassMan::InterruptForRestart
43
37
  ProconBypassMan::PrintMessageCommand.execute(text: "設定ファイルの再読み込みを開始します")
44
38
  Process.kill("USR2", child_pid)
45
39
  Process.wait
@@ -68,13 +68,22 @@ module ProconBypassMan
68
68
  end
69
69
 
70
70
  def self.register_schedules
71
- register(
72
- schedule: Schedule.new(
73
- klass: ProconBypassMan::SyncDeviceStatsJob,
74
- args: [->{ ProconBypassMan::DeviceStatus.current }],
75
- interval: 60,
71
+ if ProconBypassMan.config.has_api_server?
72
+ register(
73
+ schedule: Schedule.new(
74
+ klass: ProconBypassMan::SyncDeviceStatsJob,
75
+ args: [->{ ProconBypassMan::DeviceStatus.current }],
76
+ interval: 60,
77
+ )
76
78
  )
77
- ) if ProconBypassMan.config.has_api_server?
79
+ register(
80
+ schedule: Schedule.new(
81
+ klass: ProconBypassMan::ReportProconPerformanceMeasurementsJob,
82
+ args: [->{ ProconBypassMan::Procon::PerformanceMeasurement.pop_measurement_collection }],
83
+ interval: 60,
84
+ )
85
+ )
86
+ end
78
87
  end
79
88
 
80
89
  # @param [Schedule] schedule
@@ -73,28 +73,32 @@ module ProconBypassMan
73
73
  def run_callbacks(kind, &block)
74
74
  chains = get_callbacks(kind) or raise("unknown callback")
75
75
  if chains.nil? || chains.empty?
76
- block.call
77
- return
76
+ return block.call
78
77
  end
79
78
 
80
79
  chains[:before]&.each do |chain|
81
80
  send chain.chain_method
82
81
  end
83
- block.call
82
+ result = block.call
84
83
  chains[:after]&.each do |chain|
85
84
  send chain.chain_method
86
85
  end
86
+
87
+ return result
87
88
  end
88
89
 
89
90
  def get_callbacks(kind) # :nodoc:
90
91
  # classに直接moduleをincludeしている場合
91
- if defined?(self.class.__callbacks)
92
+ if defined?(self.class.__callbacks) && !self.class.respond_to?(:callbacks)
92
93
  return self.class.__callbacks[kind.to_sym]
93
94
  end
94
95
 
95
96
  list = self.class.callbacks.flat_map { |callback_mod|
96
97
  callback_mod.__callbacks && callback_mod.__callbacks[kind.to_sym]
97
98
  }.compact
99
+ if(self.class.respond_to?(:__callbacks) && chain = self.class.__callbacks[kind.to_sym])
100
+ list << chain
101
+ end
98
102
  table = {}
99
103
  table[:before] = list.flat_map { |x| x[:before] }.compact
100
104
  table[:after] = list.flat_map { |x| x[:after] }.compact
@@ -0,0 +1,60 @@
1
+ require 'drb/drb'
2
+
3
+ # NOTE マスタープロセスでstart_distributed_object!をコールする必要がある
4
+ # forkをしたらそのさきでDRb.start_serviceをコールする必要がある
5
+ module ProconBypassMan::CanOverProcess
6
+ PROTOCOL = "drbunix".freeze
7
+
8
+ def self.extended(mod)
9
+ mod.singleton_class.attr_accessor :drb_server, :drb_server_thread
10
+ end
11
+
12
+ # @return [void]
13
+ def start_distributed_object!
14
+ return unless enable?
15
+
16
+ FileUtils.rm_rf(socket_file_path) if File.exist?(socket_file_path)
17
+ begin
18
+ self.drb_server = DRb.start_service(socket_path, distributed_class.new, safe_level: 1)
19
+ rescue Errno::EADDRINUSE => e
20
+ ProconBypassMan.logger.error e
21
+ raise
22
+ end
23
+
24
+ self.drb_server_thread =
25
+ Thread.new do
26
+ DRb.thread.join
27
+ end
28
+ end
29
+ alias start! start_distributed_object!
30
+
31
+ # @return [void]
32
+ def shutdown_distributed_object
33
+ if self.drb_server
34
+ self.drb_server_thread&.kill
35
+ self.drb_server_thread = nil
36
+ self.drb_server.stop_service
37
+ end
38
+ end
39
+ alias shutdown shutdown_distributed_object
40
+
41
+ # @return [Boolean]
42
+ def enable?
43
+ raise NotImplementedError
44
+ end
45
+
46
+ # @return [String]
47
+ def socket_file_path
48
+ raise NotImplementedError
49
+ end
50
+
51
+ # @return [any]
52
+ def distributed_class
53
+ raise NotImplementedError
54
+ end
55
+
56
+ # @return [String]
57
+ def socket_path
58
+ "#{PROTOCOL}:#{socket_file_path}".freeze
59
+ end
60
+ end
@@ -0,0 +1,8 @@
1
+ class ProconBypassMan::GC
2
+ def self.stop_gc_in(&block)
3
+ ::GC.disable
4
+ result = block.call
5
+ ::GC.enable
6
+ return result
7
+ end
8
+ end
@@ -26,9 +26,9 @@ module ProconBypassMan
26
26
  end
27
27
  end
28
28
 
29
- def initialize(path: , server_pool: , retry_on_connection_error: false)
30
- @server_pool = server_pool
31
- @uri = URI.parse("#{server_pool.server}#{path}")
29
+ def initialize(path: , server: , retry_on_connection_error: false)
30
+ @server = server
31
+ @uri = URI.parse("#{server}#{path}")
32
32
  @retry_on_connection_error = retry_on_connection_error
33
33
  end
34
34
 
@@ -76,14 +76,13 @@ module ProconBypassMan
76
76
  return response.body
77
77
  end
78
78
  else
79
- @server_pool.next!
80
79
  ProconBypassMan.logger.error("#{@uri}から200以外(#{response.code})が帰ってきました. #{response.body}")
81
80
  end
82
81
  end
83
82
 
84
83
  def handle_request
85
84
  raise "need block" unless block_given?
86
- if @server_pool.server.nil?
85
+ if @server.nil?
87
86
  ProconBypassMan.logger.info('送信先が未設定なのでスキップしました')
88
87
  return
89
88
  end
@@ -94,6 +93,10 @@ module ProconBypassMan
94
93
  sleep(10)
95
94
  retry
96
95
  end
96
+ rescue Timeout::Error
97
+ ProconBypassMan.logger.error(e)
98
+ sleep(10)
99
+ retry
97
100
  rescue => e
98
101
  puts e
99
102
  ProconBypassMan.logger.error(e)
@@ -102,5 +105,5 @@ module ProconBypassMan
102
105
  end
103
106
 
104
107
  if $0 == __FILE__
105
- ProconBypassMan::HttpClient.new(path: '/', server_pool: nil, retry_on_connection_error: false).get(response_body: '')
108
+ ProconBypassMan::HttpClient.new(path: '/', server: nil, retry_on_connection_error: false).get(response_body: '')
106
109
  end
@@ -0,0 +1,20 @@
1
+ module ProconBypassMan
2
+ class LoadAgv
3
+ PATH = '/proc/loadavg'
4
+
5
+ # @return [[Integer, Integer, Integer]]
6
+ def get
7
+ loadavg = get_proc_loadavg
8
+ loadavg =~ /^([0-9.]+)\s([0-9.]+)\s([0-9.]+)/
9
+ return [$1.to_f, $2.to_f, $3.to_f].join("-")
10
+ rescue Errno::ENOENT
11
+ ""
12
+ end
13
+
14
+ private
15
+
16
+ def get_proc_loadavg
17
+ File.read('/proc/loadavg')
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,7 @@
1
+ module ProconBypassMan
2
+ class ProconPerformanceHttpClient < HttpClient
3
+ def post(body: )
4
+ super(request_body: { body: body })
5
+ end
6
+ end
7
+ end