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 +4 -4
- data/CHANGELOG.md +3 -0
- data/Gemfile.lock +1 -1
- data/README.md +24 -3
- data/lib/blue_green_process/master_process.rb +44 -2
- data/lib/blue_green_process/version.rb +1 -1
- data/lib/blue_green_process/worker_process.rb +8 -2
- data/lib/blue_green_process.rb +22 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c8905db7b63e35a80a3fa1272553fa4f84002e06747501b5749110a6edfed79e
|
4
|
+
data.tar.gz: 467fbb4d348d6fae9cfc70a013f88a560cc69a97690451d0b53908585d312e20
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f042564e95f91038d87faaae43d891d798204784a27f0b2fb1a038df195717c58755c7a65531216d97f4477296dee1775119ba1c01560c7fb067a336c1b613aa
|
7
|
+
data.tar.gz: 28d937c6280847b821ef49f4c247649549a13bf4a5c0f62d444cb6d5c391d88c491ac2d2fcca38a56947e4eb66b5583200885b4cc4e4f40c63cd61c2a8ac5bc1
|
data/CHANGELOG.md
CHANGED
data/Gemfile.lock
CHANGED
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
|
45
|
-
|
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
|
@@ -47,7 +47,9 @@ module BlueGreenProcess
|
|
47
47
|
end
|
48
48
|
|
49
49
|
def wait_response
|
50
|
-
|
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
|
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
|
data/lib/blue_green_process.rb
CHANGED
@@ -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.
|
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-
|
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:
|