riser 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +926 -0
- data/Rakefile +31 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/example/halo.html +18 -0
- data/example/halo.rb +171 -0
- data/example/halo.yml +21 -0
- data/example/local_services.rb +60 -0
- data/example/multiproc_server.rb +21 -0
- data/example/simple_count.rb +52 -0
- data/example/simple_daemon.rb +22 -0
- data/example/simple_key_count.rb +65 -0
- data/example/simple_server.rb +20 -0
- data/example/simple_services.rb +60 -0
- data/example/simple_tls.rb +32 -0
- data/lib/riser/daemon.rb +579 -0
- data/lib/riser/poll.rb +35 -0
- data/lib/riser/resource.rb +386 -0
- data/lib/riser/server.rb +869 -0
- data/lib/riser/services.rb +631 -0
- data/lib/riser/stream.rb +115 -0
- data/lib/riser/temppath.rb +25 -0
- data/lib/riser/test.rb +42 -0
- data/lib/riser/version.rb +10 -0
- data/lib/riser.rb +28 -0
- data/riser.gemspec +35 -0
- metadata +129 -0
data/lib/riser/daemon.rb
ADDED
@@ -0,0 +1,579 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'logger'
|
4
|
+
require 'syslog/logger'
|
5
|
+
require 'yaml'
|
6
|
+
|
7
|
+
module Riser
|
8
|
+
class StatusFile
|
9
|
+
def initialize(filename)
|
10
|
+
@filename = filename
|
11
|
+
end
|
12
|
+
|
13
|
+
def open
|
14
|
+
@file = File.open(@filename, File::WRONLY | File::CREAT, 0644)
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
18
|
+
def close
|
19
|
+
@file.close
|
20
|
+
nil
|
21
|
+
end
|
22
|
+
|
23
|
+
def lock
|
24
|
+
@file.flock(File::LOCK_EX | File::LOCK_NB)
|
25
|
+
end
|
26
|
+
|
27
|
+
def write(text)
|
28
|
+
@file.truncate(0)
|
29
|
+
@file.seek(0)
|
30
|
+
ret_val = @file.write(text)
|
31
|
+
@file.flush
|
32
|
+
ret_val
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class RootProcess
|
37
|
+
class SystemOperation
|
38
|
+
def initialize(logger, module_Process: Process, class_IO: IO)
|
39
|
+
@logger = logger
|
40
|
+
@Process = module_Process
|
41
|
+
@IO = class_IO
|
42
|
+
end
|
43
|
+
|
44
|
+
def get_server_address(sockaddr_get)
|
45
|
+
begin
|
46
|
+
address_config = sockaddr_get.call
|
47
|
+
rescue
|
48
|
+
@logger.error("failed to get server address [#{$!}]")
|
49
|
+
@logger.debug($!) if @logger.debug?
|
50
|
+
return
|
51
|
+
end
|
52
|
+
|
53
|
+
server_address = SocketAddress.parse(address_config)
|
54
|
+
unless (server_address) then
|
55
|
+
@logger.error("failed to parse server address: #{address_config.inspect}")
|
56
|
+
end
|
57
|
+
server_address
|
58
|
+
end
|
59
|
+
|
60
|
+
def get_server_socket(server_address)
|
61
|
+
begin
|
62
|
+
server_address.open_server
|
63
|
+
rescue
|
64
|
+
@logger.error("failed to open server socket: #{server_address} [#{$!}]")
|
65
|
+
@logger.debug($!) if @logger.debug?
|
66
|
+
nil
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def send_signal(pid, signal)
|
71
|
+
begin
|
72
|
+
@Process.kill(signal, pid)
|
73
|
+
rescue
|
74
|
+
@logger.error("failed to send signal (#{signal}) to process (pid: #{pid}) [#{$!}]")
|
75
|
+
@logger.debug($!) if @logger.debug?
|
76
|
+
nil
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def wait(pid, flags=0)
|
81
|
+
begin
|
82
|
+
@Process.wait(pid, flags)
|
83
|
+
rescue
|
84
|
+
@logger.error("failed to wait(2) for process (pid: #{pid}) [#{$!}]")
|
85
|
+
@logger.debug($!) if @logger.debug?
|
86
|
+
nil
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def pipe
|
91
|
+
begin
|
92
|
+
@IO.pipe
|
93
|
+
rescue
|
94
|
+
@logger.error("failed to pipe(2) [#{$!}]")
|
95
|
+
@logger.debug($!) if @logger.debug?
|
96
|
+
nil
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def fork
|
101
|
+
begin
|
102
|
+
@Process.fork{ yield }
|
103
|
+
rescue
|
104
|
+
@logger.error("failed to fork(2) [#{$!}]")
|
105
|
+
@logger.debug($!) if @logger.debug?
|
106
|
+
nil
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def gets(io)
|
111
|
+
begin
|
112
|
+
io.gets
|
113
|
+
rescue
|
114
|
+
@logger.error("failed to get line from #{io.inspect} [#{$!}]")
|
115
|
+
@logger.debug($!) if @logger.debug?
|
116
|
+
nil
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def close(io)
|
121
|
+
begin
|
122
|
+
io.close
|
123
|
+
io
|
124
|
+
rescue
|
125
|
+
@logger.error("failed to close(2) #{io.inspect} [#{$!}]")
|
126
|
+
@logger.debug($!) if @logger.debug?
|
127
|
+
nil
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
include ServerSignal
|
133
|
+
|
134
|
+
def initialize(logger, sockaddr_get, server_polling_interval_seconds, server_restart_overlap_seconds=0, euid=nil, egid=nil, &block) # :yields: socket_server
|
135
|
+
@logger = logger
|
136
|
+
@sockaddr_get = sockaddr_get
|
137
|
+
@server_polling_interval_seconds = server_polling_interval_seconds
|
138
|
+
@server_restart_overlap_seconds = server_restart_overlap_seconds
|
139
|
+
@euid = euid
|
140
|
+
@egid = egid
|
141
|
+
@server_setup = block
|
142
|
+
@sysop = SystemOperation.new(@logger)
|
143
|
+
@stop_state = nil
|
144
|
+
@in_server_polling_sleep = false
|
145
|
+
@signal_operation_queue = []
|
146
|
+
@process_wait_count_table = {}
|
147
|
+
end
|
148
|
+
|
149
|
+
def server_polling_sleep
|
150
|
+
catch(:end_of_server_polling_sleep) {
|
151
|
+
begin
|
152
|
+
@in_server_polling_sleep = true
|
153
|
+
sleep(@server_polling_interval_seconds)
|
154
|
+
ensure
|
155
|
+
@in_server_polling_sleep = false
|
156
|
+
end
|
157
|
+
}
|
158
|
+
end
|
159
|
+
private :server_polling_sleep
|
160
|
+
|
161
|
+
def interrupt_server_polling_sleep
|
162
|
+
if (@in_server_polling_sleep) then
|
163
|
+
throw(:end_of_server_polling_sleep)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
private :interrupt_server_polling_sleep
|
167
|
+
|
168
|
+
# should be called from signal(2) handler
|
169
|
+
def signal_stop_graceful
|
170
|
+
@stop_state ||= :graceful
|
171
|
+
interrupt_server_polling_sleep
|
172
|
+
nil
|
173
|
+
end
|
174
|
+
|
175
|
+
# should be called from signal(2) handler
|
176
|
+
def signal_stop_forced
|
177
|
+
@stop_state ||= :forced
|
178
|
+
interrupt_server_polling_sleep
|
179
|
+
nil
|
180
|
+
end
|
181
|
+
|
182
|
+
# should be called from signal(2) handler
|
183
|
+
def signal_restart_graceful
|
184
|
+
@signal_operation_queue << :restart_graceful
|
185
|
+
interrupt_server_polling_sleep
|
186
|
+
nil
|
187
|
+
end
|
188
|
+
|
189
|
+
# should be called from signal(2) handler
|
190
|
+
def signal_restart_forced
|
191
|
+
@signal_operation_queue << :restart_forced
|
192
|
+
interrupt_server_polling_sleep
|
193
|
+
nil
|
194
|
+
end
|
195
|
+
|
196
|
+
# should be called from signal(2) handler
|
197
|
+
def signal_stat_get(reset: true)
|
198
|
+
if (reset) then
|
199
|
+
@signal_operation_queue << :stat_get_and_reset
|
200
|
+
else
|
201
|
+
@signal_operation_queue << :stat_get_no_reset
|
202
|
+
end
|
203
|
+
interrupt_server_polling_sleep
|
204
|
+
nil
|
205
|
+
end
|
206
|
+
|
207
|
+
# should be called from signal(2) handler
|
208
|
+
def signal_stat_stop
|
209
|
+
@signal_operation_queue << :stat_stop
|
210
|
+
interrupt_server_polling_sleep
|
211
|
+
nil
|
212
|
+
end
|
213
|
+
|
214
|
+
# should be called from signal(2) handler
|
215
|
+
def signal_server_down
|
216
|
+
interrupt_server_polling_sleep
|
217
|
+
nil
|
218
|
+
end
|
219
|
+
|
220
|
+
def server_stop_graceful(pid)
|
221
|
+
@sysop.send_signal(pid, SIGNAL_STOP_GRACEFUL)
|
222
|
+
end
|
223
|
+
private :server_stop_graceful
|
224
|
+
|
225
|
+
def server_stop_forced(pid)
|
226
|
+
@sysop.send_signal(pid, SIGNAL_STOP_FORCED)
|
227
|
+
end
|
228
|
+
private :server_stop_forced
|
229
|
+
|
230
|
+
def run_server(server_socket)
|
231
|
+
read_write = @sysop.pipe
|
232
|
+
unless (read_write) then
|
233
|
+
@logger.error('failed to start server.')
|
234
|
+
return
|
235
|
+
end
|
236
|
+
latch_read_io, latch_write_io = read_write
|
237
|
+
|
238
|
+
pid = @sysop.fork{
|
239
|
+
begin
|
240
|
+
latch_read_io.close
|
241
|
+
|
242
|
+
if (@egid) then
|
243
|
+
@logger.info("change group privilege from #{Process::GID.eid} to #{@egid}")
|
244
|
+
Process::GID.change_privilege(@egid)
|
245
|
+
end
|
246
|
+
|
247
|
+
if (@euid) then
|
248
|
+
@logger.info("change user privilege from #{Process::UID.eid} to #{@euid}")
|
249
|
+
Process::UID.change_privilege(@euid)
|
250
|
+
end
|
251
|
+
|
252
|
+
server = SocketServer.new
|
253
|
+
@server_setup.call(server)
|
254
|
+
server.setup(server_socket)
|
255
|
+
Signal.trap(SIGNAL_STOP_GRACEFUL) { server.signal_stop_graceful }
|
256
|
+
Signal.trap(SIGNAL_STOP_FORCED) { server.signal_stop_forced }
|
257
|
+
Signal.trap(SIGNAL_STAT_GET_AND_RESET) { server.signal_stat_get(reset: true) }
|
258
|
+
Signal.trap(SIGNAL_STAT_GET_NO_RESET) { server.signal_stat_get(reset: false) }
|
259
|
+
Signal.trap(SIGNAL_STAT_STOP) { server.signal_stat_stop }
|
260
|
+
rescue
|
261
|
+
@logger.error("failed to setup server (pid: #{$$}) [#{$!}]")
|
262
|
+
@logger.debug($!) if @logger.debug?
|
263
|
+
raise
|
264
|
+
end
|
265
|
+
@logger.close
|
266
|
+
latch_write_io.puts("server process (pid: #{$$}) is ready to go.")
|
267
|
+
|
268
|
+
server.start(server_socket)
|
269
|
+
}
|
270
|
+
|
271
|
+
unless (pid) then
|
272
|
+
@sysop.close(latch_read_io)
|
273
|
+
@sysop.close(latch_write_io)
|
274
|
+
@logger.error('failed to start server.')
|
275
|
+
return
|
276
|
+
end
|
277
|
+
|
278
|
+
error_count = 0
|
279
|
+
@sysop.close(latch_write_io) or error_count += 1
|
280
|
+
server_messg = @sysop.gets(latch_read_io)
|
281
|
+
@sysop.close(latch_read_io) or error_count += 1
|
282
|
+
|
283
|
+
if (server_messg) then
|
284
|
+
@logger.debug("[server process message] #{server_messg.chomp}") if @logger.debug?
|
285
|
+
else
|
286
|
+
@logger.error("no response from server process (pid: #{pid})")
|
287
|
+
end
|
288
|
+
|
289
|
+
if (! server_messg || error_count > 0) then
|
290
|
+
@sysop.send_signal(pid, SIGNAL_STOP_FORCED) or @logger.error("failed to kill abnormal server process (pid: #{pid})")
|
291
|
+
@process_wait_count_table[pid] = 0
|
292
|
+
@logger.error('failed to start server.')
|
293
|
+
return
|
294
|
+
end
|
295
|
+
|
296
|
+
pid
|
297
|
+
end
|
298
|
+
private :run_server
|
299
|
+
|
300
|
+
# should be executed on the main thread sharing the stack with
|
301
|
+
# signal(2) handlers
|
302
|
+
def start
|
303
|
+
@logger.info('daemon start.')
|
304
|
+
|
305
|
+
unless (server_address = @sysop.get_server_address(@sockaddr_get)) then
|
306
|
+
@logger.fatal('failed to start daemon.')
|
307
|
+
return 1
|
308
|
+
end
|
309
|
+
|
310
|
+
unless (server_socket = @sysop.get_server_socket(server_address)) then
|
311
|
+
@logger.fatal('failed to start daemon.')
|
312
|
+
return 1
|
313
|
+
end
|
314
|
+
@logger.info("open server socket: #{server_socket.local_address.inspect_sockaddr}")
|
315
|
+
|
316
|
+
unless (server_pid = run_server(server_socket)) then
|
317
|
+
@logger.fatal('failed to start daemon.')
|
318
|
+
return 1
|
319
|
+
end
|
320
|
+
@logger.info("server process start (pid: #{server_pid})")
|
321
|
+
|
322
|
+
@logger.info("start server polling (interval seconds: #{@server_polling_interval_seconds})")
|
323
|
+
until (@stop_state)
|
324
|
+
server_polling_sleep
|
325
|
+
if (server_pid) then
|
326
|
+
@logger.debug("server polling... (pid: #{server_pid})") if @logger.debug?
|
327
|
+
else
|
328
|
+
@logger.debug('server polling...') if @logger.debug?
|
329
|
+
end
|
330
|
+
|
331
|
+
if (! server_pid || @sysop.wait(server_pid, Process::WNOHANG)) then
|
332
|
+
if (server_pid) then
|
333
|
+
@logger.warn("found server down (pid: #{server_pid}) and restart server.")
|
334
|
+
else
|
335
|
+
@logger.warn('found server down and restart server.')
|
336
|
+
end
|
337
|
+
if (server_pid = run_server(server_socket)) then
|
338
|
+
@logger.info("server process start (pid: #{server_pid})")
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
342
|
+
while (! @stop_state && server_pid && sig_ope = @signal_operation_queue.shift)
|
343
|
+
case (sig_ope)
|
344
|
+
when :restart_graceful, :restart_forced
|
345
|
+
if (next_server_address = @sysop.get_server_address(@sockaddr_get)) then
|
346
|
+
if (next_server_address != server_address) then
|
347
|
+
if (next_server_socket = @sysop.get_server_socket(next_server_address)) then
|
348
|
+
@logger.info("open server socket: #{next_server_socket.local_address.inspect_sockaddr}")
|
349
|
+
@logger.info("close server socket: #{server_socket.local_address.inspect_sockaddr}")
|
350
|
+
@sysop.close(server_socket) or @logger.warn("failed to close server socket (#{server_address})")
|
351
|
+
server_socket = next_server_socket
|
352
|
+
server_address = next_server_address
|
353
|
+
else
|
354
|
+
@logger.warn("server socket continue: #{server_socket.local_address.inspect_sockaddr}")
|
355
|
+
end
|
356
|
+
end
|
357
|
+
else
|
358
|
+
@logger.warn("server socket continue: #{server_socket.local_address.inspect_sockaddr}")
|
359
|
+
end
|
360
|
+
|
361
|
+
case (sig_ope)
|
362
|
+
when :restart_graceful
|
363
|
+
@logger.info("server graceful restart (pid: #{server_pid})")
|
364
|
+
when :restart_forced
|
365
|
+
@logger.info("server forced restart (pid: #{server_pid})")
|
366
|
+
else
|
367
|
+
@logger.warn("internal warning: unknown signal operation <#{sig_ope.inspect}>")
|
368
|
+
end
|
369
|
+
|
370
|
+
if (next_pid = run_server(server_socket)) then
|
371
|
+
@logger.info("server process start (pid: #{next_pid})")
|
372
|
+
|
373
|
+
if (@server_restart_overlap_seconds > 0) then
|
374
|
+
@logger.info("server restart overlap (interval seconds: #{@server_restart_overlap_seconds})")
|
375
|
+
sleep(@server_restart_overlap_seconds)
|
376
|
+
end
|
377
|
+
|
378
|
+
case (sig_ope)
|
379
|
+
when :restart_graceful
|
380
|
+
@logger.info("server graceful stop (pid: #{server_pid})")
|
381
|
+
server_stop_graceful(server_pid)
|
382
|
+
when :restart_forced
|
383
|
+
@logger.info("server forced stop (pid: #{server_pid})")
|
384
|
+
server_stop_forced(server_pid)
|
385
|
+
else
|
386
|
+
@logger.warn("internal warning: unknown signal operation <#{sig_ope.inspect}>")
|
387
|
+
end
|
388
|
+
|
389
|
+
@process_wait_count_table[server_pid] = 0
|
390
|
+
server_pid = next_pid
|
391
|
+
else
|
392
|
+
@logger.warn("server continue (pid: #{server_pid})")
|
393
|
+
end
|
394
|
+
when :stat_get_and_reset
|
395
|
+
@logger.info("stat get(reset: true) (pid: #{server_pid})")
|
396
|
+
@sysop.send_signal(server_pid, SIGNAL_STAT_GET_AND_RESET) or @logger.error("failed to stat get(reset: true) (pid: #{server_pid})")
|
397
|
+
when :stat_get_no_reset
|
398
|
+
@logger.info("stat get(reset: false) (pid: #{server_pid})")
|
399
|
+
@sysop.send_signal(server_pid, SIGNAL_STAT_GET_NO_RESET) or @logger.error("failed to stat get(reset: false) (pid: #{server_pid})")
|
400
|
+
when :stat_stop
|
401
|
+
@logger.info("stat stop (pid: #{server_pid})")
|
402
|
+
@sysop.send_signal(server_pid, SIGNAL_STAT_STOP) or @logger.error("failed to stat stop (pid: #{server_pid})")
|
403
|
+
else
|
404
|
+
@logger.warn("internal warning: unknown signal operation <#{sig_ope.inspect}>")
|
405
|
+
end
|
406
|
+
end
|
407
|
+
|
408
|
+
for pid in @process_wait_count_table.keys
|
409
|
+
if (@sysop.wait(pid, Process::WNOHANG)) then
|
410
|
+
@logger.info("server stop completed (pid: #{pid})")
|
411
|
+
@process_wait_count_table.delete(pid)
|
412
|
+
else
|
413
|
+
@process_wait_count_table[pid] += 1
|
414
|
+
if (@process_wait_count_table[pid] >= 2) then
|
415
|
+
@logger.warn("not stopped server process (pid: #{pid})")
|
416
|
+
end
|
417
|
+
end
|
418
|
+
end
|
419
|
+
end
|
420
|
+
|
421
|
+
if (server_pid) then
|
422
|
+
case (@stop_state)
|
423
|
+
when :graceful
|
424
|
+
@logger.info("server graceful stop (pid: #{server_pid})")
|
425
|
+
unless (server_stop_graceful(server_pid)) then
|
426
|
+
@logger.fatal('failed to stop daemon.')
|
427
|
+
return 1
|
428
|
+
end
|
429
|
+
unless (@sysop.wait(server_pid)) then
|
430
|
+
@logger.fatal('failed to stop daemon.')
|
431
|
+
return 1
|
432
|
+
end
|
433
|
+
when :forced
|
434
|
+
@logger.info("server forced stop (pid: #{server_pid})")
|
435
|
+
unless (server_stop_forced(server_pid)) then
|
436
|
+
@logger.fatal('failed to stop daemon.')
|
437
|
+
return 1
|
438
|
+
end
|
439
|
+
unless (@sysop.wait(server_pid)) then
|
440
|
+
@logger.fatal('failed to stop daemon.')
|
441
|
+
return 1
|
442
|
+
end
|
443
|
+
else
|
444
|
+
@logger.error("internal error: unknown stop state <#{@stop_state.inspect}>")
|
445
|
+
return 1
|
446
|
+
end
|
447
|
+
else
|
448
|
+
@logger.warn('no server to stop.')
|
449
|
+
end
|
450
|
+
|
451
|
+
@logger.info('daemon stop.')
|
452
|
+
return 0
|
453
|
+
end
|
454
|
+
end
|
455
|
+
|
456
|
+
module Daemon
|
457
|
+
include ServerSignal
|
458
|
+
|
459
|
+
def get_id(name, id_mod) # :nodoc:
|
460
|
+
if (name) then
|
461
|
+
case (name)
|
462
|
+
when Integer
|
463
|
+
name
|
464
|
+
when /\A \d+ \z/x
|
465
|
+
name.to_i
|
466
|
+
else
|
467
|
+
id_mod.from_name(name)
|
468
|
+
end
|
469
|
+
end
|
470
|
+
end
|
471
|
+
module_function :get_id
|
472
|
+
|
473
|
+
def get_uid(user)
|
474
|
+
get_id(user, Process::UID)
|
475
|
+
end
|
476
|
+
module_function :get_uid
|
477
|
+
|
478
|
+
def get_gid(group)
|
479
|
+
get_id(group, Process::GID)
|
480
|
+
end
|
481
|
+
module_function :get_gid
|
482
|
+
|
483
|
+
DEFAULT = {
|
484
|
+
daemonize: true,
|
485
|
+
daemon_name: 'ruby',
|
486
|
+
daemon_debug: $DEBUG,
|
487
|
+
daemon_nochdir: true,
|
488
|
+
status_file: nil,
|
489
|
+
listen_address: nil,
|
490
|
+
server_polling_interval_seconds: 3,
|
491
|
+
server_restart_overlap_seconds: 0,
|
492
|
+
server_privileged_user: nil,
|
493
|
+
server_privileged_group: nil,
|
494
|
+
|
495
|
+
signal_stop_graceful: SIGNAL_STOP_GRACEFUL,
|
496
|
+
signal_stop_forced: SIGNAL_STOP_FORCED,
|
497
|
+
signal_stat_get_and_reset: SIGNAL_STAT_GET_AND_RESET,
|
498
|
+
signal_stat_get_no_reset: SIGNAL_STAT_GET_NO_RESET,
|
499
|
+
signal_stat_stop: SIGNAL_STAT_STOP,
|
500
|
+
signal_restart_graceful: SIGNAL_RESTART_GRACEFUL,
|
501
|
+
signal_restart_forced: SIGNAL_RESTART_FORCED
|
502
|
+
}.freeze
|
503
|
+
|
504
|
+
# should be executed on the main thread sharing the stack with
|
505
|
+
# signal(2) handlers
|
506
|
+
def start_daemon(config, &block) # :yields: socket_server
|
507
|
+
c = DEFAULT.dup
|
508
|
+
c.update(config)
|
509
|
+
|
510
|
+
if (c[:status_file]) then
|
511
|
+
status_file = StatusFile.new(c[:status_file])
|
512
|
+
status_file.open
|
513
|
+
status_file.lock or abort("#{c[:daemon_name]} daemon is already running.")
|
514
|
+
end
|
515
|
+
|
516
|
+
if (c[:daemonize]) then
|
517
|
+
logger = Syslog::Logger.new(c[:daemon_name])
|
518
|
+
def logger.close
|
519
|
+
Syslog::Logger.syslog = nil
|
520
|
+
Syslog.close
|
521
|
+
nil
|
522
|
+
end
|
523
|
+
else
|
524
|
+
logger = Logger.new(STDOUT)
|
525
|
+
logger.progname = c[:daemon_name]
|
526
|
+
def logger.close # not close STDOUT
|
527
|
+
end
|
528
|
+
end
|
529
|
+
|
530
|
+
if (c[:daemon_debug]) then
|
531
|
+
logger.level = Logger::DEBUG
|
532
|
+
else
|
533
|
+
logger.level = Logger::INFO
|
534
|
+
end
|
535
|
+
|
536
|
+
if (c[:listen_address].respond_to? :call) then
|
537
|
+
sockaddr_get = c[:listen_address]
|
538
|
+
else
|
539
|
+
sockaddr_get = proc{ c[:listen_address] }
|
540
|
+
end
|
541
|
+
|
542
|
+
euid = get_uid(c[:server_privileged_user])
|
543
|
+
egid = get_gid(c[:server_privileged_group])
|
544
|
+
|
545
|
+
root_process = RootProcess.new(logger, sockaddr_get, c[:server_polling_interval_seconds], c[:server_restart_overlap_seconds], euid, egid, &block)
|
546
|
+
[ [ :signal_stop_graceful, proc{ root_process.signal_stop_graceful } ],
|
547
|
+
[ :signal_stop_forced, proc{ root_process.signal_stop_forced } ],
|
548
|
+
[ :signal_stat_get_and_reset, proc{ root_process.signal_stat_get(reset: true) } ],
|
549
|
+
[ :signal_stat_get_no_reset, proc{ root_process.signal_stat_get(reset: false) } ],
|
550
|
+
[ :signal_stat_stop, proc{ root_process.signal_stat_stop } ],
|
551
|
+
[ :signal_restart_graceful, proc{ root_process.signal_restart_graceful } ],
|
552
|
+
[ :signal_restart_forced, proc{ root_process.signal_restart_forced } ]
|
553
|
+
].each{|sig_key, sig_hook|
|
554
|
+
if (signal = c[sig_key]) then
|
555
|
+
Signal.trap(signal, &sig_hook)
|
556
|
+
end
|
557
|
+
}
|
558
|
+
Signal.trap(:CHLD) { root_process.signal_server_down }
|
559
|
+
|
560
|
+
if (c[:daemonize]) then
|
561
|
+
Process.daemon(c[:daemon_nochdir], true)
|
562
|
+
end
|
563
|
+
|
564
|
+
# update after process ID changes in daemonization.
|
565
|
+
if (c[:status_file]) then
|
566
|
+
status_file.write({ 'pid' => $$ }.to_yaml)
|
567
|
+
end
|
568
|
+
|
569
|
+
status = root_process.start
|
570
|
+
exit(status)
|
571
|
+
end
|
572
|
+
module_function :start_daemon
|
573
|
+
end
|
574
|
+
end
|
575
|
+
|
576
|
+
# Local Variables:
|
577
|
+
# mode: Ruby
|
578
|
+
# indent-tabs-mode: nil
|
579
|
+
# End:
|
data/lib/riser/poll.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'io/wait'
|
4
|
+
|
5
|
+
module Riser
|
6
|
+
class ReadPoll
|
7
|
+
def initialize(read_io)
|
8
|
+
@read_io = read_io
|
9
|
+
reset_timer
|
10
|
+
end
|
11
|
+
|
12
|
+
def reset_timer
|
13
|
+
@t0 = Time.now
|
14
|
+
self
|
15
|
+
end
|
16
|
+
|
17
|
+
def interval_seconds
|
18
|
+
Time.now - @t0
|
19
|
+
end
|
20
|
+
|
21
|
+
def read_poll(timeout_seconds)
|
22
|
+
readable = @read_io.wait_readable(timeout_seconds)
|
23
|
+
reset_timer unless readable.nil?
|
24
|
+
readable
|
25
|
+
end
|
26
|
+
|
27
|
+
alias poll read_poll
|
28
|
+
alias call read_poll
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Local Variables:
|
33
|
+
# mode: Ruby
|
34
|
+
# indent-tabs-mode: nil
|
35
|
+
# End:
|