serverengine 1.6.4 → 2.0.0pre1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/Changelog +11 -0
- data/README.md +31 -3
- data/Rakefile +16 -3
- data/appveyor.yml +11 -5
- data/examples/server.rb +138 -0
- data/examples/spawn_worker_script.rb +38 -0
- data/lib/serverengine/blocking_flag.rb +2 -3
- data/lib/serverengine/command_sender.rb +89 -0
- data/lib/serverengine/config_loader.rb +2 -0
- data/lib/serverengine/daemon.rb +114 -86
- data/lib/serverengine/daemon_logger.rb +3 -139
- data/lib/serverengine/embedded_server.rb +2 -0
- data/lib/serverengine/multi_process_server.rb +28 -7
- data/lib/serverengine/multi_spawn_server.rb +17 -18
- data/lib/serverengine/multi_thread_server.rb +6 -0
- data/lib/serverengine/multi_worker_server.rb +14 -0
- data/lib/serverengine/privilege.rb +57 -0
- data/lib/serverengine/process_manager.rb +66 -48
- data/lib/serverengine/server.rb +45 -11
- data/lib/serverengine/signal_thread.rb +0 -2
- data/lib/serverengine/signals.rb +31 -0
- data/lib/serverengine/socket_manager.rb +3 -5
- data/lib/serverengine/socket_manager_unix.rb +1 -0
- data/lib/serverengine/socket_manager_win.rb +4 -2
- data/lib/serverengine/supervisor.rb +105 -25
- data/lib/serverengine/utils.rb +23 -0
- data/lib/serverengine/version.rb +1 -1
- data/lib/serverengine/worker.rb +10 -7
- data/lib/serverengine.rb +9 -27
- data/serverengine.gemspec +12 -1
- data/spec/daemon_logger_spec.rb +17 -12
- data/spec/daemon_spec.rb +147 -24
- data/spec/multi_process_server_spec.rb +59 -7
- data/spec/server_worker_context.rb +104 -0
- data/spec/signal_thread_spec.rb +61 -56
- data/spec/supervisor_spec.rb +113 -99
- metadata +40 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9c2c41ca45cff7f607a22a6861bd7b55e03a70b7
|
4
|
+
data.tar.gz: 97948ab60c218ef17becfb05723270592cc7540c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 38ff87ed7b173030bb5293c0d3e89a824efae90b9e87c5a6fefa22f61c3e14b737c4e28cc92e783fc51568f517a5aea5393b69a46de7c8aa26892f24ec0190d9
|
7
|
+
data.tar.gz: 143bfeb1386750fc4275e68d9555551e450ffa57e9c9a408a6fb2e313b421301e4bef62d320ad3a8f0906936bc43f453a92d895ec1103a2735478f1561b3d76a
|
data/.gitignore
CHANGED
data/Changelog
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
2016-08-23 version 2.0.0:
|
2
|
+
|
3
|
+
* Add windows-pr gem dependency to get ruby_bin_path correctly
|
4
|
+
* Add command sender feature to use pipe to control workers for Windows
|
5
|
+
* Delete MultiprocessLogDevice implementation to use Ruby's one always. This
|
6
|
+
means removal of backward workaround code for Ruby < 2.1.
|
7
|
+
* Refactor modules and methods to clean internal file dependency Internal
|
8
|
+
symbol `ServerEngine::Daemon::Signals` is moved to `ServerEngine::Signals`
|
9
|
+
* Add example script to run servers
|
10
|
+
* Fix required Ruby version to 2.1 or later
|
11
|
+
|
1
12
|
2016-05-19 version 1.6.4:
|
2
13
|
|
3
14
|
* Refactor to delete some warnings
|
data/README.md
CHANGED
@@ -68,7 +68,7 @@ se = ServerEngine.create(nil, MyWorker, {
|
|
68
68
|
se.run
|
69
69
|
```
|
70
70
|
|
71
|
-
Send `TERM` signal to kill the daemon. See also **Signals** section bellow for details.
|
71
|
+
Send `TERM` signal (or `KILL` on Windows) to kill the daemon. See also **Signals** section bellow for details.
|
72
72
|
|
73
73
|
|
74
74
|
### Multiprocess server
|
@@ -141,6 +141,12 @@ ServerEngine provides **worker_type: "spawn"** for those platforms (This is stil
|
|
141
141
|
|
142
142
|
What you need to implement at least to use worker_type: "spawn" is `def spawn(process_manager)` method. You will call `process_manager.spawn` at the method, where `spawn` is same with `Process.spawn` excepting return value.
|
143
143
|
|
144
|
+
In addition, Windows does not support signals. ServerEngine provides **command_sender: "pipe"** for Windows (and for other platforms, if you want to use it).
|
145
|
+
When using **command_sender: "pipe"**, the child process have to handle commands sent from parent process via STDIN.
|
146
|
+
On Windows, **command_sender: "pipe"** is default.
|
147
|
+
|
148
|
+
You can call `Server#stop(stop_graceful)` and `Server#restart(stop_graceful)` instead of sending signals.
|
149
|
+
|
144
150
|
```ruby
|
145
151
|
module MyWorker
|
146
152
|
def spawn(process_manager)
|
@@ -155,8 +161,20 @@ module MyWorker
|
|
155
161
|
logger = ServerEngine::DaemonLogger.new(conf[:log] || STDOUT, conf)
|
156
162
|
|
157
163
|
@stop = false
|
158
|
-
|
159
|
-
|
164
|
+
command_pipe = STDIN.dup
|
165
|
+
STDIN.reopen(File::NULL)
|
166
|
+
Thread.new do
|
167
|
+
until @stop
|
168
|
+
case command_pipe.gets.chomp
|
169
|
+
when "GRACEFUL_STOP"
|
170
|
+
@stop = true
|
171
|
+
when "IMMEDIATE_STOP"
|
172
|
+
@stop = true
|
173
|
+
when "GRACEFUL_RESTART", "IMMEDIATE_RESTART"
|
174
|
+
# do something...
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
160
178
|
|
161
179
|
until @stop
|
162
180
|
logger.info 'Awesome work!'
|
@@ -169,6 +187,7 @@ end
|
|
169
187
|
|
170
188
|
se = ServerEngine.create(nil, MyWorker, {
|
171
189
|
worker_type: 'spawn',
|
190
|
+
command_sender: 'pipe',
|
172
191
|
log: 'myserver.log',
|
173
192
|
})
|
174
193
|
se.run
|
@@ -213,6 +232,7 @@ se = ServerEngine.create(nil, MyWorker, {
|
|
213
232
|
se.run
|
214
233
|
```
|
215
234
|
|
235
|
+
This auto restart reature will be suppressed for workers which exits with exit code specified by `unrecoverable_exit_codes`. At this case, whole process will exit without error (exit code 0).
|
216
236
|
|
217
237
|
## Live restart
|
218
238
|
|
@@ -304,6 +324,10 @@ Send `USR2` signal to reload configuration file.
|
|
304
324
|
Immediate shutdown and restart send SIGQUIT signal to worker processes which kills the processes.
|
305
325
|
Graceful shutdown and restart call `Worker#stop` method and wait for completion of `Worker#run` method.
|
306
326
|
|
327
|
+
Note that signals are not supported on Windows.
|
328
|
+
You have to use piped command instead of signals on Windows.
|
329
|
+
See also **Multiprocess server on Windows and JRuby platforms** section.
|
330
|
+
|
307
331
|
|
308
332
|
## Utilities
|
309
333
|
|
@@ -388,6 +412,8 @@ se = ServerEngine.create(MyServer, MyWorker, {
|
|
388
412
|
se.run
|
389
413
|
```
|
390
414
|
|
415
|
+
See also [examples](https://github.com/fluent/serverengine/tree/master/examples).
|
416
|
+
|
391
417
|
|
392
418
|
## Module API
|
393
419
|
|
@@ -464,6 +490,8 @@ Available methods are different depending on `worker_type`. ServerEngine support
|
|
464
490
|
- **worker_immediate_kill_interval** sets the first interval of QUIT signals in seconds (default: 10) [dynamic reloadable]
|
465
491
|
- **worker_immediate_kill_interval_increment** sets increment of QUIT signal interval in seconds (default: 10) [dynamic reloadable]
|
466
492
|
- **worker_immediate_kill_timeout** sets promotion timeout from QUIT to KILL signal in seconds. -1 means no timeout (default: 600) [dynamic reloadable]
|
493
|
+
- **unrecoverable_exit_codes** handles worker processes, which exits with code included in this value, as unrecoverable (not to restart) (default: [])
|
494
|
+
- **stop_immediately_at_unrecoverable_exit** stops server immediately if a worker exits with unrecoverable exit status (default: false)
|
467
495
|
- Multiprocess spawn server: available only when `worker_type` is "spawn"
|
468
496
|
- all parameters of multiprocess server excepting worker_process_name
|
469
497
|
- **worker_reload_signal** sets the signal to notice configuration reload to a spawned process. Set nil to disable (default: nil)
|
data/Rakefile
CHANGED
@@ -6,8 +6,21 @@ require 'rake/clean'
|
|
6
6
|
|
7
7
|
require 'rspec/core/rake_task'
|
8
8
|
|
9
|
-
RSpec::Core::RakeTask.new(:spec)
|
10
|
-
|
9
|
+
RSpec::Core::RakeTask.new(:spec)
|
10
|
+
task :default => [:spec, :build]
|
11
|
+
|
12
|
+
# 1. update Changelog and lib/serverengine/version.rb
|
13
|
+
# 2. bundle && bundle exec rake build:all
|
14
|
+
# 3. release 3 packages built on pkg/ directory
|
15
|
+
namespace :build do
|
16
|
+
desc 'Build gems for all platforms'
|
17
|
+
task :all do
|
18
|
+
Bundler.with_clean_env do
|
19
|
+
%w[ruby x86-mingw32 x64-mingw32].each do |name|
|
20
|
+
ENV['GEM_BUILD_FAKE_PLATFORM'] = name
|
21
|
+
Rake::Task["build"].execute
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
11
25
|
end
|
12
26
|
|
13
|
-
task :default => [:spec, :build]
|
data/appveyor.yml
CHANGED
@@ -10,9 +10,15 @@ test_script:
|
|
10
10
|
|
11
11
|
environment:
|
12
12
|
matrix:
|
13
|
-
- ruby_version: "
|
14
|
-
|
15
|
-
- ruby_version: "
|
16
|
-
|
13
|
+
- ruby_version: "23-x64"
|
14
|
+
devkit: C:\Ruby23-x64\DevKit
|
15
|
+
- ruby_version: "23"
|
16
|
+
devkit: C:\Ruby23\DevKit
|
17
|
+
- ruby_version: "22-x64"
|
18
|
+
devkit: C:\Ruby23-x64\DevKit
|
17
19
|
- ruby_version: "22"
|
18
|
-
|
20
|
+
devkit: C:\Ruby23\DevKit
|
21
|
+
- ruby_version: "21-x64"
|
22
|
+
devkit: C:\Ruby23-x64\DevKit
|
23
|
+
- ruby_version: "21"
|
24
|
+
devkit: C:\Ruby23\DevKit
|
data/examples/server.rb
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
require 'serverengine'
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'optparse'
|
5
|
+
|
6
|
+
# This is a script to run ServerEngine and SocketManager as a real process.
|
7
|
+
# bundle exec ruby example/server.rb [-t TYPE] [-w NUM]
|
8
|
+
# available type of workers are: embedded(default), process, thread, spawn
|
9
|
+
|
10
|
+
foreground = false
|
11
|
+
supervisor = false
|
12
|
+
worker_type = nil
|
13
|
+
workers = 4
|
14
|
+
exit_with_code = nil
|
15
|
+
exit_at_seconds = 5
|
16
|
+
exit_at_random = false
|
17
|
+
stop_immediately_at_exit = false
|
18
|
+
unrecoverable_exit_codes = []
|
19
|
+
|
20
|
+
opt = OptionParser.new
|
21
|
+
opt.on('-f'){ foreground = true }
|
22
|
+
opt.on('-x'){ supervisor = true }
|
23
|
+
opt.on('-t TYPE'){|v| worker_type = v }
|
24
|
+
opt.on('-w NUM'){|v| workers = v.to_i }
|
25
|
+
opt.on('-e NUM'){|v| exit_with_code = v.to_i }
|
26
|
+
opt.on('-s NUM'){|v| exit_at_seconds = v.to_i }
|
27
|
+
opt.on('-r'){ exit_at_random = true }
|
28
|
+
opt.on('-i'){ stop_immediately_at_exit = true }
|
29
|
+
opt.on('-u NUM'){|v| unrecoverable_exit_codes << v.to_i }
|
30
|
+
opt.parse!(ARGV)
|
31
|
+
|
32
|
+
if exit_with_code
|
33
|
+
ENV['EXIT_WITH_CODE'] = exit_with_code.to_s
|
34
|
+
ENV['EXIT_AT_SECONDS'] = exit_at_seconds.to_s
|
35
|
+
if exit_at_random
|
36
|
+
ENV['EXIT_AT_RANDOM'] = 'true'
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
module MyServer
|
41
|
+
attr_reader :socket_manager_path
|
42
|
+
|
43
|
+
def before_run
|
44
|
+
@socket_manager_path = ServerEngine::SocketManager::Server.generate_path
|
45
|
+
@socket_manager_server = ServerEngine::SocketManager::Server.open(@socket_manager_path)
|
46
|
+
rescue Exception => e
|
47
|
+
logger.error "unexpected error in server, class #{e.class}: #{e.message}"
|
48
|
+
raise
|
49
|
+
end
|
50
|
+
|
51
|
+
def after_run
|
52
|
+
logger.info "Server stopped."
|
53
|
+
@socket_manager_server.close
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
module MyWorker
|
58
|
+
def initialize
|
59
|
+
@stop = false
|
60
|
+
@socket_manager = ServerEngine::SocketManager::Client.new(server.socket_manager_path)
|
61
|
+
@exit_with_code = ENV.key?('EXIT_WITH_CODE') ? ENV['EXIT_WITH_CODE'].to_i : nil
|
62
|
+
@exit_at_seconds = ENV.key?('EXIT_AT_SECONDS') ? ENV['EXIT_AT_SECONDS'].to_i : nil
|
63
|
+
@exit_at_random = ENV.key?('EXIT_AT_RANDOM')
|
64
|
+
end
|
65
|
+
|
66
|
+
def main
|
67
|
+
# test to listen the same port
|
68
|
+
logger.info "Starting to run Worker."
|
69
|
+
_listen_sock = @socket_manager.listen_tcp('0.0.0.0', 12345)
|
70
|
+
stop_at = if @exit_with_code
|
71
|
+
stop_seconds = @exit_at_random ? rand(@exit_at_seconds) : @exit_at_seconds
|
72
|
+
logger.info "Stop #{stop_seconds} seconds later with code #{@exit_with_code}."
|
73
|
+
Time.now + stop_seconds
|
74
|
+
else
|
75
|
+
nil
|
76
|
+
end
|
77
|
+
until @stop
|
78
|
+
if stop_at && Time.now >= stop_at
|
79
|
+
logger.info "Exitting with code #{@exit_with_code}"
|
80
|
+
exit! @exit_with_code
|
81
|
+
end
|
82
|
+
logger.info "Awesome work!"
|
83
|
+
sleep 1
|
84
|
+
end
|
85
|
+
logger.info "Exitting"
|
86
|
+
rescue Exception => e
|
87
|
+
logger.warn "unexpected error, class #{e.class}: #{e.message}"
|
88
|
+
raise
|
89
|
+
end
|
90
|
+
|
91
|
+
def stop
|
92
|
+
@stop = true
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
module MySpawnWorker
|
97
|
+
def spawn(process_manager)
|
98
|
+
env = {
|
99
|
+
'SERVER_ENGINE_CONFIG' => config.to_json,
|
100
|
+
'SERVER_ENGINE_SOCKET_MANAGER_PATH' => server.socket_manager_path,
|
101
|
+
}
|
102
|
+
if ENV['EXIT_WITH_CODE']
|
103
|
+
env['EXIT_WITH_CODE'] = ENV['EXIT_WITH_CODE']
|
104
|
+
env['EXIT_AT_SECONDS'] = ENV['EXIT_AT_SECONDS']
|
105
|
+
if ENV['EXIT_AT_RANDOM']
|
106
|
+
env['EXIT_AT_RANDOM'] = 'true'
|
107
|
+
end
|
108
|
+
end
|
109
|
+
process_manager.spawn(env, "ruby", File.expand_path("../spawn_worker_script.rb", __FILE__))
|
110
|
+
rescue Exception => e
|
111
|
+
logger.error "unexpected error, class #{e.class}: #{e.message}"
|
112
|
+
raise
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
opts = {
|
117
|
+
daemonize: !foreground,
|
118
|
+
daemon_process_name: 'mydaemon',
|
119
|
+
supervisor: supervisor,
|
120
|
+
log: 'myserver.log',
|
121
|
+
pid_path: 'myserver.pid',
|
122
|
+
worker_type: worker_type,
|
123
|
+
workers: workers,
|
124
|
+
}
|
125
|
+
if stop_immediately_at_exit
|
126
|
+
opts[:stop_immediately_at_unrecoverable_exit] = true
|
127
|
+
end
|
128
|
+
unless unrecoverable_exit_codes.empty?
|
129
|
+
opts[:unrecoverable_exit_codes] = unrecoverable_exit_codes
|
130
|
+
end
|
131
|
+
|
132
|
+
worker_klass = MyWorker
|
133
|
+
if worker_type == 'spawn'
|
134
|
+
worker_klass = MySpawnWorker
|
135
|
+
end
|
136
|
+
se = ServerEngine.create(MyServer, worker_klass, opts)
|
137
|
+
|
138
|
+
se.run
|
@@ -0,0 +1,38 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path("../..", __FILE__)
|
2
|
+
|
3
|
+
require 'serverengine'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
begin
|
7
|
+
conf = JSON.parse(ENV['SERVER_ENGINE_CONFIG'], symbolize_names: true)
|
8
|
+
logger = ServerEngine::DaemonLogger.new(conf[:log] || STDOUT, conf)
|
9
|
+
logger.info "Starting to run Worker."
|
10
|
+
socket_manager = ServerEngine::SocketManager::Client.new(ENV['SERVER_ENGINE_SOCKET_MANAGER_PATH'])
|
11
|
+
exit_with_code = ENV.key?('EXIT_WITH_CODE') ? ENV['EXIT_WITH_CODE'].to_i : nil
|
12
|
+
exit_at_seconds = ENV.key?('EXIT_AT_SECONDS') ? ENV['EXIT_AT_SECONDS'].to_i : nil
|
13
|
+
exit_at_random = ENV.key?('EXIT_AT_RANDOM')
|
14
|
+
stop_at = if exit_with_code
|
15
|
+
stop_seconds = exit_at_random ? rand(exit_at_seconds) : exit_at_seconds
|
16
|
+
logger.info "Stop #{stop_seconds} seconds later with code #{exit_with_code}."
|
17
|
+
Time.now + stop_seconds
|
18
|
+
else
|
19
|
+
nil
|
20
|
+
end
|
21
|
+
|
22
|
+
@stop = false
|
23
|
+
trap(:SIGTERM) { @stop = true }
|
24
|
+
trap(:SIGINT) { @stop = true }
|
25
|
+
|
26
|
+
_listen_sock = socket_manager.listen_tcp('0.0.0.0', 12345)
|
27
|
+
until @stop
|
28
|
+
if stop_at && Time.now >= stop_at
|
29
|
+
logger.info "Exitting with code #{exit_with_code}"
|
30
|
+
exit! exit_with_code
|
31
|
+
end
|
32
|
+
logger.info 'Awesome work!'
|
33
|
+
sleep 1
|
34
|
+
end
|
35
|
+
logger.info 'Exitting'
|
36
|
+
rescue Exception => e
|
37
|
+
logger.error "unexpected error in spawn worker, class #{e.class}: #{e.message}"
|
38
|
+
end
|
@@ -15,10 +15,9 @@
|
|
15
15
|
# See the License for the specific language governing permissions and
|
16
16
|
# limitations under the License.
|
17
17
|
#
|
18
|
-
|
19
|
-
|
20
|
-
require 'thread'
|
18
|
+
require 'thread'
|
21
19
|
|
20
|
+
module ServerEngine
|
22
21
|
class BlockingFlag
|
23
22
|
def initialize
|
24
23
|
@set = false
|
@@ -0,0 +1,89 @@
|
|
1
|
+
#
|
2
|
+
# ServerEngine
|
3
|
+
#
|
4
|
+
# Copyright (C) 2012-2013 FURUHASHI Sadayuki
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
#
|
18
|
+
require 'serverengine/signals'
|
19
|
+
|
20
|
+
module ServerEngine
|
21
|
+
module CommandSender
|
22
|
+
# requires send_signal method or @pid
|
23
|
+
module Signal
|
24
|
+
private
|
25
|
+
def _stop(graceful)
|
26
|
+
_send_signal(!ServerEngine.windows? && graceful ? Signals::GRACEFUL_STOP : Signals::IMMEDIATE_STOP)
|
27
|
+
end
|
28
|
+
|
29
|
+
def _restart(graceful)
|
30
|
+
_send_signal(graceful ? Signals::GRACEFUL_RESTART : Signals::IMMEDIATE_RESTART)
|
31
|
+
end
|
32
|
+
|
33
|
+
def _reload
|
34
|
+
_send_signal(Signals::RELOAD)
|
35
|
+
end
|
36
|
+
|
37
|
+
def _detach
|
38
|
+
_send_signal(Signals::DETACH)
|
39
|
+
end
|
40
|
+
|
41
|
+
def _dump
|
42
|
+
_send_signal(Signals::DUMP)
|
43
|
+
end
|
44
|
+
|
45
|
+
def _send_signal(sig)
|
46
|
+
if respond_to?(:send_signal, true)
|
47
|
+
send_signal(sig)
|
48
|
+
else
|
49
|
+
Process.kill(sig, @pid)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# requires @command_sender_pipe
|
55
|
+
module Pipe
|
56
|
+
private
|
57
|
+
def _stop(graceful)
|
58
|
+
begin
|
59
|
+
_send_command(graceful ? "GRACEFUL_STOP" : "IMMEDIATE_STOP")
|
60
|
+
rescue Errno::EPIPE
|
61
|
+
# already stopped, then nothing to do
|
62
|
+
ensure
|
63
|
+
@command_sender_pipe.close rescue nil
|
64
|
+
@command_sender_pipe = nil
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def _restart(graceful)
|
69
|
+
_send_command(graceful ? "GRACEFUL_RESTART" : "IMMEDIATE_RESTART")
|
70
|
+
end
|
71
|
+
|
72
|
+
def _reload
|
73
|
+
_send_command("RELOAD")
|
74
|
+
end
|
75
|
+
|
76
|
+
def _detach
|
77
|
+
_send_command("DETACH")
|
78
|
+
end
|
79
|
+
|
80
|
+
def _dump
|
81
|
+
_send_command("DUMP")
|
82
|
+
end
|
83
|
+
|
84
|
+
def _send_command(cmd)
|
85
|
+
@command_sender_pipe.write cmd + "\n"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|