blue_green_process 0.1.3 → 0.1.4

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: 89de1bb6ab2d7f30cf4063f1f04411da882e1061550603ee8ca866839a62f9d0
4
- data.tar.gz: dc64126db9c11c6e03dfa80be32aed24e0a7142f463efd04915729f335233c68
3
+ metadata.gz: c8905db7b63e35a80a3fa1272553fa4f84002e06747501b5749110a6edfed79e
4
+ data.tar.gz: 467fbb4d348d6fae9cfc70a013f88a560cc69a97690451d0b53908585d312e20
5
5
  SHA512:
6
- metadata.gz: '00874bdfeba757a3e8cc5bba6cebdf8a8bfa63d2ab8ff4779f26a9ce5bd8a5afd9ac933e4833b8a0042ce55cefda62d69f70077396d8f6df9bb64961d2e12f70'
7
- data.tar.gz: c5de3504ad7ec738260fcf4969ea9cb1cba38539f582ad122c159f543e05666ac1cc3dc7d8f1111134a5d8ad8ae4392006db8d7c4893f4d1214ae9bcea98361f
6
+ metadata.gz: f042564e95f91038d87faaae43d891d798204784a27f0b2fb1a038df195717c58755c7a65531216d97f4477296dee1775119ba1c01560c7fb067a336c1b613aa
7
+ data.tar.gz: 28d937c6280847b821ef49f4c247649549a13bf4a5c0f62d444cb6d5c391d88c491ac2d2fcca38a56947e4eb66b5583200885b4cc4e4f40c63cd61c2a8ac5bc1
data/CHANGELOG.md CHANGED
@@ -1,3 +1,6 @@
1
+ ## [0.1.4] - 2022-12-
2
+ * BlueGreenProcess.terminate_workers_immediately を呼び出すことで、シグナル経由で終了できるようになりました
3
+
1
4
  ## [0.1.3] - 2022-9-5
2
5
  * 単一プロセスでの実行を延長するとGC.startを実行しなくなりました
3
6
  * 長時間にわたって延長する時は呼び出し側でGC.startを実行してください
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- blue_green_process (0.1.3)
4
+ blue_green_process (0.1.4)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -2,6 +2,29 @@
2
2
 
3
3
  A library that solves GC bottlenecks with multi-process.
4
4
 
5
+ ```mermaid
6
+ sequenceDiagram
7
+ autonumber
8
+ loop
9
+ Master->>+Blue: be active
10
+ Blue->>-Master: response
11
+ Master->>+Blue: work
12
+ Blue->>-Master: response
13
+ Master->>+Blue: be inactive
14
+ Blue->>-Master: response
15
+ Blue-->>Blue: GC.start
16
+ Master->>+Green: be active
17
+ Green->>-Master: response
18
+ Master->>+Green: work
19
+ Green->>-Master: response
20
+ Master->>+Green: be inactive
21
+ Green->>-Master: response
22
+ Green->>Green: GC.start
23
+ end
24
+
25
+ ```
26
+
27
+
5
28
  ## Installation
6
29
 
7
30
  Install the gem and add to the application's Gemfile by executing:
@@ -31,6 +54,7 @@ end
31
54
  sleep(1)
32
55
 
33
56
  process.shutdown
57
+ # or BlueGreenProcess.terminate_workers_immediately
34
58
  Process.waitall
35
59
  ```
36
60
 
@@ -148,6 +172,3 @@ The gem is available as open source under the terms of the [MIT License](https:/
148
172
 
149
173
  ## TODO
150
174
  * shutdownしないでプロセスを停止したときにSIGINTを受け取りたい
151
- * runしている間にsignalをもらったらすぐにdieを送りたい
152
- * inactiveからactiveへの切り替えになる時間を測定したい
153
- * GCが長引いてactiveプロセスが処理開始に時間がかかるので
@@ -24,10 +24,18 @@ module BlueGreenProcess
24
24
  @max_work = max_work
25
25
  end
26
26
 
27
+ # @return [Array<Integer>]
28
+ # 削除予定
27
29
  def pids
28
30
  @processes.map(&:pid)
29
31
  end
30
32
 
33
+ # @return [Array<Integer>]
34
+ def worker_pids
35
+ @processes.map(&:pid)
36
+ end
37
+
38
+ # @return [BlueGreenProcess::WorkerProcess]
31
39
  def fork_process(label:, worker_instance:)
32
40
  child_read, parent_write = IO.pipe
33
41
  parent_read, child_write = IO.pipe
@@ -39,10 +47,12 @@ module BlueGreenProcess
39
47
  parent_write.close
40
48
  parent_read.close
41
49
  process_status = :inactive
50
+ handle_signal(pipes: [child_read, child_write])
42
51
 
43
52
  loop do
44
- data = child_read.gets&.strip
45
- json = JSON.parse(data)
53
+ next unless (data = child_read.gets)
54
+
55
+ json = JSON.parse(data.strip)
46
56
  command = json["c"]
47
57
  case command
48
58
  when BlueGreenProcess::PROCESS_COMMAND_DIE, nil, ""
@@ -76,6 +86,8 @@ module BlueGreenProcess
76
86
  puts "unknown. from #{label}(#{$PROCESS_ID})"
77
87
  exit 1
78
88
  end
89
+ rescue IOError # NOTE: シグナル経由でpipeが破棄された時にこれが発生する
90
+ exit 127
79
91
  end
80
92
 
81
93
  exit 0
@@ -87,6 +99,7 @@ module BlueGreenProcess
87
99
  BlueGreenProcess::WorkerProcess.new(pid, label, parent_read, parent_write)
88
100
  end
89
101
 
102
+ # @return [void]
90
103
  def work
91
104
  active_process do |process|
92
105
  @max_work.times do
@@ -99,6 +112,7 @@ module BlueGreenProcess
99
112
  raise eval(e.error_class), e.message
100
113
  end
101
114
 
115
+ # @return [void]
102
116
  def shutdown
103
117
  @processes.each(&:shutdown)
104
118
  Process.waitall
@@ -106,6 +120,7 @@ module BlueGreenProcess
106
120
 
107
121
  private
108
122
 
123
+ # @return [void]
109
124
  def active_process
110
125
  active_process = nil
111
126
  @stage[!@stage_state].be_inactive
@@ -126,5 +141,32 @@ module BlueGreenProcess
126
141
 
127
142
  true
128
143
  end
144
+
145
+ # @return [void]
146
+ # シグナルを受け取ってpipeをcloseする
147
+ def handle_signal(pipes:)
148
+ Thread.new do
149
+ self_read, self_write = IO.pipe
150
+ %w[INT TERM].each do |sig|
151
+ trap sig do
152
+ self_write.puts(sig)
153
+ end
154
+ rescue ArgumentError
155
+ warn("Signal #{sig} not supported")
156
+ end
157
+
158
+ begin
159
+ while (readable_io = IO.select([self_read]))
160
+ signal = readable_io.first[0].gets.strip
161
+ case signal
162
+ when "INT", "TERM"
163
+ raise Interrupt
164
+ end
165
+ end
166
+ rescue Interrupt
167
+ pipes.each(&:close)
168
+ end
169
+ end
170
+ end
129
171
  end
130
172
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module BlueGreenProcess
4
- VERSION = "0.1.3"
4
+ VERSION = "0.1.4"
5
5
  end
@@ -47,7 +47,9 @@ module BlueGreenProcess
47
47
  end
48
48
 
49
49
  def wait_response
50
- response = JSON.parse(read)
50
+ return unless (text = read)
51
+
52
+ response = JSON.parse(text.strip)
51
53
  BlueGreenProcess::SharedVariable.instance.restore(response["data"])
52
54
  case response["c"]
53
55
  when BlueGreenProcess::RESPONSE_OK
@@ -60,11 +62,15 @@ module BlueGreenProcess
60
62
  end
61
63
 
62
64
  def read
63
- rpipe.gets.strip
65
+ rpipe.gets
66
+ rescue IOError
67
+ # NOTE: シグナル経由でpipeが破棄された時にこれが発生する
64
68
  end
65
69
 
66
70
  def write(token, args = {})
67
71
  wpipe.puts({ c: token }.merge!(args).to_json)
72
+ rescue Errno::EPIPE
73
+ # NOTE: シグナル経由でpipeが破棄された時にこれが発生する
68
74
  end
69
75
 
70
76
  def enforce_to_be_active
@@ -13,6 +13,8 @@ require "json"
13
13
  require "singleton"
14
14
 
15
15
  module BlueGreenProcess
16
+ PID_PATH = "/tmp/pbm_blue_green_process_pids"
17
+
16
18
  PROCESS_STATUS_ACTIVE = :active
17
19
  PROCESS_STATUS_INACTIVE = :inactive
18
20
 
@@ -25,7 +27,9 @@ module BlueGreenProcess
25
27
  RESPONSE_ERROR = "ERR"
26
28
 
27
29
  def self.new(worker_instance:, max_work:)
28
- BlueGreenProcess::MasterProcess.new(worker_instance: worker_instance, max_work: max_work)
30
+ master_process = BlueGreenProcess::MasterProcess.new(worker_instance: worker_instance, max_work: max_work)
31
+ File.write(PID_PATH, master_process.worker_pids.join(","))
32
+ master_process
29
33
  end
30
34
 
31
35
  def self.configure
@@ -50,4 +54,21 @@ module BlueGreenProcess
50
54
  @config = Config.new
51
55
  @performance = Performance.new
52
56
  end
57
+
58
+ # @return [void]
59
+ def self.terminate_workers_immediately
60
+ worker_pids = nil
61
+ begin
62
+ worker_pids = File.read(PID_PATH).split(",").map(&:to_i)
63
+ rescue Errno::ENOENT
64
+ warn("#{PID_PATH}にファイルがありませんでした")
65
+ return
66
+ end
67
+
68
+ worker_pids.each do |worker_pid|
69
+ Process.kill "TERM", worker_pid
70
+ rescue Errno::ESRCH => e
71
+ warn("BlueGreenProcess workerプロセス(#{worker_pid})の終了に失敗しました。", e.message)
72
+ end
73
+ end
53
74
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: blue_green_process
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - jiikko
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-09-05 00:00:00.000000000 Z
11
+ date: 2022-12-12 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: A library that solves GC bottlenecks with multi-process.
14
14
  email: