riser 0.1.0
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.
- 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:
|