riser 0.1.1 → 0.1.2

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: e26229a7967de4c918147e37649406d03d58cdee805eace413c4954e620a721a
4
- data.tar.gz: fb420260978813955e399b828df5172a339acc60d5682eeb4173c6a93318d598
3
+ metadata.gz: cb038d800b97433c3499cb880acc77e0513d6dab1d18eace369137a98870cd8b
4
+ data.tar.gz: e4b2a6ab5cc93fa3e84c0dcdd53038e879d54e51ee2007f702a1afeb10c45409
5
5
  SHA512:
6
- metadata.gz: 647c1ea473d0beac010774c07c69166f617236d1e4be65741925533274a8c909ccc870f6d69b3c2fe461a0026d9d0fb2edb7424be990ce695a644e2042078e53
7
- data.tar.gz: c2256038205ede27cd679385965a2f18785777edfc5e03a6e43fd9f3a0bbd412f3628efdcca0b1c0fb0ca3712d44fb0513dac2b474ac44ea9c0f6f9a67a63e0f
6
+ metadata.gz: 4b5fdb35eb7ea3c7f9b535e5d857acb7bb85b671db989ed90123ead48d1079606afbe35a9f0c970a4ddfe62c21c32246468406c33739fad5a037b5e61b92d525
7
+ data.tar.gz: 71a67816a2048bd849eb12801a40c8114b446bafbbde210e253c172af915026d524c976f6068472ebf747af2b9a0ad6b79d9e3344b74b58bf96c874337db3368
data/LICENSE.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2018 TOKI Yoshinori
3
+ Copyright (c) 2018-2019 TOKI Yoshinori
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -463,7 +463,8 @@ Riser::Daemon.start_daemon(daemonize: false,
463
463
  socket << 'pid: ' << services.call_service(:pid_single) << "\n"
464
464
  when '/sticky'
465
465
  key = query || 'default'
466
- socket << 'key: ' << key << ', pid: ' << services.call_service(:pid_stickty, key) << "\n"
466
+ socket << 'key: ' << key << "\n"
467
+ socket << 'pid: ' << services.call_service(:pid_stickty, key) << "\n"
467
468
  else
468
469
  socket << "unknown path: #{path}\n"
469
470
  end
@@ -587,17 +588,23 @@ the web service's result of 'sticky process' pattern.
587
588
 
588
589
  ```
589
590
  $ curl http://localhost:8000/sticky
590
- key: default, pid: 3181
591
+ key: default
592
+ pid: 3181
591
593
  $ curl http://localhost:8000/sticky
592
- key: default, pid: 3181
594
+ key: default
595
+ pid: 3181
593
596
  $ curl http://localhost:8000/sticky?foo
594
- key: foo, pid: 3179
597
+ key: foo
598
+ pid: 3179
595
599
  $ curl http://localhost:8000/sticky?foo
596
- key: foo, pid: 3179
600
+ key: foo
601
+ pid: 3179
597
602
  $ curl http://localhost:8000/sticky?bar
598
- key: bar, pid: 3185
603
+ key: bar
604
+ pid: 3185
599
605
  $ curl http://localhost:8000/sticky?bar
600
- key: bar, pid: 3185
606
+ key: bar
607
+ pid: 3185
601
608
  ```
602
609
 
603
610
  In the 'sticky process' pattern, the same process id will be given for
@@ -651,7 +658,8 @@ Riser::Daemon.start_daemon(daemonize: false,
651
658
  socket << 'pid: ' << services.call_service(:pid_single) << "\n"
652
659
  when '/sticky'
653
660
  key = query || 'default'
654
- socket << 'key: ' << key << ', pid: ' << services.call_service(:pid_stickty, key) << "\n"
661
+ socket << 'key: ' << key << "\n"
662
+ socket << 'pid: ' << services.call_service(:pid_stickty, key) << "\n"
655
663
  else
656
664
  socket << "unknown path: #{path}\n"
657
665
  end
@@ -711,17 +719,23 @@ pid: 3855
711
719
 
712
720
  ```
713
721
  $ curl http://localhost:8000/sticky
714
- key: default, pid: 3855
722
+ key: default
723
+ pid: 3855
715
724
  $ curl http://localhost:8000/sticky
716
- key: default, pid: 3855
725
+ key: default
726
+ pid: 3855
717
727
  $ curl http://localhost:8000/sticky?foo
718
- key: foo, pid: 3855
728
+ key: foo
729
+ pid: 3855
719
730
  $ curl http://localhost:8000/sticky?foo
720
- key: foo, pid: 3855
731
+ key: foo
732
+ pid: 3855
721
733
  $ curl http://localhost:8000/sticky?bar
722
- key: bar, pid: 3855
734
+ key: bar
735
+ pid: 3855
723
736
  $ curl http://localhost:8000/sticky?bar
724
- key: bar, pid: 3855
737
+ key: bar
738
+ pid: 3855
725
739
  ```
726
740
 
727
741
  ### dRuby Services Callbacks
@@ -819,8 +833,8 @@ Riser::Daemon.start_daemon(daemonize: false,
819
833
  builder.at_create{|key|
820
834
  PStore.new("simple_key_count-#{key}.pstore", true)
821
835
  }
822
- builder.at_destroy{
823
- # nothing to do.
836
+ builder.at_destroy{|pstore|
837
+ # nothing to do about `pstore'.
824
838
  }
825
839
  })
826
840
 
@@ -42,7 +42,8 @@ Riser::Daemon.start_daemon(daemonize: false,
42
42
  socket << 'pid: ' << services.call_service(:pid_single) << "\n"
43
43
  when '/sticky'
44
44
  key = query || 'default'
45
- socket << 'key: ' << key << ', pid: ' << services.call_service(:pid_stickty, key) << "\n"
45
+ socket << 'key: ' << key << "\n"
46
+ socket << 'pid: ' << services.call_service(:pid_stickty, key) << "\n"
46
47
  else
47
48
  socket << "unknown path: #{path}\n"
48
49
  end
@@ -15,8 +15,8 @@ Riser::Daemon.start_daemon(daemonize: false,
15
15
  builder.at_create{|key|
16
16
  PStore.new("simple_key_count-#{key}.pstore", true)
17
17
  }
18
- builder.at_destroy{
19
- # nothing to do.
18
+ builder.at_destroy{|pstore|
19
+ # nothing to do about `pstore'.
20
20
  }
21
21
  })
22
22
 
@@ -42,7 +42,8 @@ Riser::Daemon.start_daemon(daemonize: false,
42
42
  socket << 'pid: ' << services.call_service(:pid_single) << "\n"
43
43
  when '/sticky'
44
44
  key = query || 'default'
45
- socket << 'key: ' << key << ', pid: ' << services.call_service(:pid_stickty, key) << "\n"
45
+ socket << 'key: ' << key << "\n"
46
+ socket << 'pid: ' << services.call_service(:pid_stickty, key) << "\n"
46
47
  else
47
48
  socket << "unknown path: #{path}\n"
48
49
  end
data/lib/riser/daemon.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
+ require 'fileutils'
3
4
  require 'logger'
4
5
  require 'syslog/logger'
5
6
  require 'yaml'
@@ -35,17 +36,19 @@ module Riser
35
36
 
36
37
  class RootProcess
37
38
  class SystemOperation
38
- def initialize(logger, module_Process: Process, class_IO: IO)
39
+ def initialize(logger, module_FileUtils: FileUtils, module_Process: Process, class_IO: IO, class_File: File)
39
40
  @logger = logger
41
+ @FileUtils = module_FileUtils
40
42
  @Process = module_Process
41
43
  @IO = class_IO
44
+ @File = class_File
42
45
  end
43
46
 
44
47
  def get_server_address(sockaddr_get)
45
48
  begin
46
49
  address_config = sockaddr_get.call
47
50
  rescue
48
- @logger.error("failed to get server address [#{$!}]")
51
+ @logger.error("failed to get server address [#{$!} (#{$!.class})]")
49
52
  @logger.debug($!) if @logger.debug?
50
53
  return
51
54
  end
@@ -61,7 +64,37 @@ module Riser
61
64
  begin
62
65
  server_address.open_server
63
66
  rescue
64
- @logger.error("failed to open server socket: #{server_address} [#{$!}]")
67
+ @logger.error("failed to open server socket: #{server_address} [#{$!} (#{$!.class})]")
68
+ @logger.debug($!) if @logger.debug?
69
+ nil
70
+ end
71
+ end
72
+
73
+ def listen(server_socket, backlog)
74
+ begin
75
+ server_socket.listen(backlog)
76
+ rescue
77
+ @logger.error("failed to listen(2) server socket with backlog: #{backlog} [#{$!} (#{$!.class})]")
78
+ @logger.debug($!) if @logger.debug?
79
+ nil
80
+ end
81
+ end
82
+
83
+ def chmod(mode, path)
84
+ begin
85
+ @FileUtils.chmod(mode, path)
86
+ rescue
87
+ @logger.error("failed to chmod(2): #{'%04o' % mode} #{path} [#{$!} (#{$!.class})]")
88
+ @logger.debug($!) if @logger.debug?
89
+ nil
90
+ end
91
+ end
92
+
93
+ def chown(owner, group, path)
94
+ begin
95
+ @FileUtils.chown(owner, group, path)
96
+ rescue
97
+ @logger.error("failed to chown(2): <#{owner}> <#{group}> <#{path}> [#{$!} (#{$!.class})]")
65
98
  @logger.debug($!) if @logger.debug?
66
99
  nil
67
100
  end
@@ -71,7 +104,7 @@ module Riser
71
104
  begin
72
105
  @Process.kill(signal, pid)
73
106
  rescue
74
- @logger.error("failed to send signal (#{signal}) to process (pid: #{pid}) [#{$!}]")
107
+ @logger.error("failed to send signal (#{signal}) to process (pid: #{pid}) [#{$!} (#{$!.class})]")
75
108
  @logger.debug($!) if @logger.debug?
76
109
  nil
77
110
  end
@@ -81,7 +114,7 @@ module Riser
81
114
  begin
82
115
  @Process.wait(pid, flags)
83
116
  rescue
84
- @logger.error("failed to wait(2) for process (pid: #{pid}) [#{$!}]")
117
+ @logger.error("failed to wait(2) for process (pid: #{pid}) [#{$!} (#{$!.class})]")
85
118
  @logger.debug($!) if @logger.debug?
86
119
  nil
87
120
  end
@@ -91,7 +124,7 @@ module Riser
91
124
  begin
92
125
  @IO.pipe
93
126
  rescue
94
- @logger.error("failed to pipe(2) [#{$!}]")
127
+ @logger.error("failed to pipe(2) [#{$!} (#{$!.class})]")
95
128
  @logger.debug($!) if @logger.debug?
96
129
  nil
97
130
  end
@@ -101,7 +134,7 @@ module Riser
101
134
  begin
102
135
  @Process.fork{ yield }
103
136
  rescue
104
- @logger.error("failed to fork(2) [#{$!}]")
137
+ @logger.error("failed to fork(2) [#{$!} (#{$!.class})]")
105
138
  @logger.debug($!) if @logger.debug?
106
139
  nil
107
140
  end
@@ -111,7 +144,7 @@ module Riser
111
144
  begin
112
145
  io.gets
113
146
  rescue
114
- @logger.error("failed to get line from #{io.inspect} [#{$!}]")
147
+ @logger.error("failed to get line from #{io.inspect} [#{$!} (#{$!.class})]")
115
148
  @logger.debug($!) if @logger.debug?
116
149
  nil
117
150
  end
@@ -122,7 +155,17 @@ module Riser
122
155
  io.close
123
156
  io
124
157
  rescue
125
- @logger.error("failed to close(2) #{io.inspect} [#{$!}]")
158
+ @logger.error("failed to close(2) #{io.inspect} [#{$!} (#{$!.class})]")
159
+ @logger.debug($!) if @logger.debug?
160
+ nil
161
+ end
162
+ end
163
+
164
+ def unlink(path)
165
+ begin
166
+ File.unlink(path)
167
+ rescue
168
+ @logger.error("failed to unlink(2): #{path} [#{$!} (#{$!.class})]")
126
169
  @logger.debug($!) if @logger.debug?
127
170
  nil
128
171
  end
@@ -258,7 +301,7 @@ module Riser
258
301
  Signal.trap(SIGNAL_STAT_GET_NO_RESET) { server.signal_stat_get(reset: false) }
259
302
  Signal.trap(SIGNAL_STAT_STOP) { server.signal_stat_stop }
260
303
  rescue
261
- @logger.error("failed to setup server (pid: #{$$}) [#{$!}]")
304
+ @logger.error("failed to setup server (pid: #{$$}) [#{$!} (#{$!.class})]")
262
305
  @logger.debug($!) if @logger.debug?
263
306
  raise
264
307
  end
@@ -313,139 +356,242 @@ module Riser
313
356
  end
314
357
  @logger.info("open server socket: #{server_socket.local_address.inspect_sockaddr}")
315
358
 
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?
359
+ begin
360
+ if (server_address.backlog) then
361
+ if (@sysop.listen(server_socket, server_address.backlog)) then
362
+ @logger.info("server socket backlog: #{server_address.backlog}")
363
+ else
364
+ @logger.warn('server socket backlog is not changed.')
365
+ end
327
366
  else
328
- @logger.debug('server polling...') if @logger.debug?
367
+ @logger.info('server socket backlog is default.')
329
368
  end
330
369
 
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.")
370
+ if (server_address.type == :unix) then
371
+ if (server_address.mode) then
372
+ if (@sysop.chmod(server_address.mode, server_address.path)) then
373
+ @logger.info("unix domain server socket mode: #{'%04o' % server_address.mode}")
374
+ else
375
+ @logger.warn('unix domain server socket mode is not changed.')
376
+ end
334
377
  else
335
- @logger.warn('found server down and restart server.')
378
+ @logger.info('unix domain server socket mode is default.')
336
379
  end
337
- if (server_pid = run_server(server_socket)) then
338
- @logger.info("server process start (pid: #{server_pid})")
380
+
381
+ if (server_address.owner || server_address.group) then
382
+ if (@sysop.chown(server_address.owner, server_address.group, server_address.path)) then
383
+ @logger.info("unix domain server socket ownership: <#{server_address.owner}> <#{server_address.group}>")
384
+ else
385
+ @logger.warn('unix domain server socket ownership is not changed.')
386
+ end
387
+ else
388
+ @logger.info('unix domain server socket ownership is default.')
339
389
  end
340
390
  end
341
391
 
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
392
+ unless (server_pid = run_server(server_socket)) then
393
+ @logger.fatal('failed to start daemon.')
394
+ return 1
395
+ end
396
+ @logger.info("server process start (pid: #{server_pid})")
397
+
398
+ @logger.info("start server polling (interval seconds: #{@server_polling_interval_seconds})")
399
+ until (@stop_state)
400
+ server_polling_sleep
401
+ if (server_pid) then
402
+ @logger.debug("server polling... (pid: #{server_pid})") if @logger.debug?
403
+ else
404
+ @logger.debug('server polling...') if @logger.debug?
405
+ end
406
+
407
+ if (! server_pid || @sysop.wait(server_pid, Process::WNOHANG)) then
408
+ if (server_pid) then
409
+ @logger.warn("found server down (pid: #{server_pid}) and restart server.")
357
410
  else
358
- @logger.warn("server socket continue: #{server_socket.local_address.inspect_sockaddr}")
411
+ @logger.warn('found server down and restart server.')
412
+ end
413
+ if (server_pid = run_server(server_socket)) then
414
+ @logger.info("server process start (pid: #{server_pid})")
359
415
  end
416
+ end
360
417
 
418
+ while (! @stop_state && server_pid && sig_ope = @signal_operation_queue.shift)
361
419
  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
420
+ when :restart_graceful, :restart_forced
421
+ if (next_server_address = @sysop.get_server_address(@sockaddr_get)) then
422
+ if (next_server_address.to_address == server_address.to_address) then
423
+ if (next_server_address.to_option != server_address.to_option) then
424
+ server_address = next_server_address
425
+ end
426
+ else
427
+ if (next_server_socket = @sysop.get_server_socket(next_server_address)) then
428
+ @logger.info("open server socket: #{next_server_socket.local_address.inspect_sockaddr}")
429
+ server_socket_local_address = server_socket.local_address # get local_address before close(2)
430
+ if (@sysop.close(server_socket)) then
431
+ @logger.info("close server socket: #{server_socket_local_address.inspect_sockaddr}")
432
+ else
433
+ @logger.warn("failed to close server socket: #{server_socket_local_address.inspect_sockaddr}")
434
+ end
435
+ if (server_address.type == :unix) then
436
+ if (@sysop.unlink(server_address.path)) then
437
+ @logger.info("delete unix server socket: #{server_address}")
438
+ else
439
+ @logger.warn("failed to delete unix server socket: #{server_address}")
440
+ end
441
+ end
442
+ server_socket = next_server_socket
443
+ server_address = next_server_address
444
+ else
445
+ @logger.warn("server socket continue: #{server_socket.local_address.inspect_sockaddr}")
446
+ end
447
+ end
448
+ else
449
+ @logger.warn("server socket continue: #{server_socket.local_address.inspect_sockaddr}")
450
+ end
369
451
 
370
- if (next_pid = run_server(server_socket)) then
371
- @logger.info("server process start (pid: #{next_pid})")
452
+ if (server_address.backlog) then
453
+ if (@sysop.listen(server_socket, server_address.backlog)) then
454
+ @logger.info("server socket backlog: #{server_address.backlog}")
455
+ else
456
+ @logger.warn('server socket backlog is not changed.')
457
+ end
458
+ else
459
+ @logger.info('server socket backlog is default.')
460
+ end
461
+
462
+ if (server_address.type == :unix) then
463
+ if (server_address.mode) then
464
+ if (@sysop.chmod(server_address.mode, server_address.path)) then
465
+ @logger.info("unix domain server socket mode: #{'%04o' % server_address.mode}")
466
+ else
467
+ @logger.warn('unix domain server socket mode is not changed.')
468
+ end
469
+ else
470
+ @logger.info('unix domain server socket mode is default.')
471
+ end
372
472
 
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)
473
+ if (server_address.owner || server_address.group) then
474
+ if (@sysop.chown(server_address.owner, server_address.group, server_address.path)) then
475
+ @logger.info("unix domain server socket ownership: <#{server_address.owner}> <#{server_address.group}>")
476
+ else
477
+ @logger.warn('unix domain server socket ownership is not changed.')
478
+ end
479
+ else
480
+ @logger.info('unix domain server socket ownership is default.')
481
+ end
376
482
  end
377
483
 
378
484
  case (sig_ope)
379
485
  when :restart_graceful
380
- @logger.info("server graceful stop (pid: #{server_pid})")
381
- server_stop_graceful(server_pid)
486
+ @logger.info("server graceful restart (pid: #{server_pid})")
382
487
  when :restart_forced
383
- @logger.info("server forced stop (pid: #{server_pid})")
384
- server_stop_forced(server_pid)
488
+ @logger.info("server forced restart (pid: #{server_pid})")
385
489
  else
386
490
  @logger.warn("internal warning: unknown signal operation <#{sig_ope.inspect}>")
387
491
  end
388
492
 
389
- @process_wait_count_table[server_pid] = 0
390
- server_pid = next_pid
493
+ if (next_pid = run_server(server_socket)) then
494
+ @logger.info("server process start (pid: #{next_pid})")
495
+
496
+ if (@server_restart_overlap_seconds > 0) then
497
+ @logger.info("server restart overlap (interval seconds: #{@server_restart_overlap_seconds})")
498
+ sleep(@server_restart_overlap_seconds)
499
+ end
500
+
501
+ case (sig_ope)
502
+ when :restart_graceful
503
+ @logger.info("server graceful stop (pid: #{server_pid})")
504
+ server_stop_graceful(server_pid)
505
+ when :restart_forced
506
+ @logger.info("server forced stop (pid: #{server_pid})")
507
+ server_stop_forced(server_pid)
508
+ else
509
+ @logger.warn("internal warning: unknown signal operation <#{sig_ope.inspect}>")
510
+ end
511
+
512
+ @process_wait_count_table[server_pid] = 0
513
+ server_pid = next_pid
514
+ else
515
+ @logger.warn("server continue (pid: #{server_pid})")
516
+ end
517
+ when :stat_get_and_reset
518
+ if (@sysop.send_signal(server_pid, SIGNAL_STAT_GET_AND_RESET)) then
519
+ @logger.info("stat get(reset: true) (pid: #{server_pid})")
520
+ else
521
+ @logger.error("failed to stat get(reset: true) (pid: #{server_pid})")
522
+ end
523
+ when :stat_get_no_reset
524
+ if (@sysop.send_signal(server_pid, SIGNAL_STAT_GET_NO_RESET)) then
525
+ @logger.info("stat get(reset: false) (pid: #{server_pid})")
526
+ else
527
+ @logger.error("failed to stat get(reset: false) (pid: #{server_pid})")
528
+ end
529
+ when :stat_stop
530
+ if (@sysop.send_signal(server_pid, SIGNAL_STAT_STOP)) then
531
+ @logger.info("stat stop (pid: #{server_pid})")
532
+ else
533
+ @logger.error("failed to stat stop (pid: #{server_pid})")
534
+ end
391
535
  else
392
- @logger.warn("server continue (pid: #{server_pid})")
536
+ @logger.warn("internal warning: unknown signal operation <#{sig_ope.inspect}>")
393
537
  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
538
  end
406
- end
407
539
 
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})")
540
+ for pid in @process_wait_count_table.keys
541
+ if (@sysop.wait(pid, Process::WNOHANG)) then
542
+ @logger.info("server stop completed (pid: #{pid})")
543
+ @process_wait_count_table.delete(pid)
544
+ else
545
+ @process_wait_count_table[pid] += 1
546
+ if (@process_wait_count_table[pid] >= 2) then
547
+ @logger.warn("not stopped server process (pid: #{pid})")
548
+ end
416
549
  end
417
550
  end
418
551
  end
419
- end
420
552
 
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
553
+ if (server_pid) then
554
+ case (@stop_state)
555
+ when :graceful
556
+ @logger.info("server graceful stop (pid: #{server_pid})")
557
+ unless (server_stop_graceful(server_pid)) then
558
+ @logger.fatal('failed to stop daemon.')
559
+ return 1
560
+ end
561
+ unless (@sysop.wait(server_pid)) then
562
+ @logger.fatal('failed to stop daemon.')
563
+ return 1
564
+ end
565
+ when :forced
566
+ @logger.info("server forced stop (pid: #{server_pid})")
567
+ unless (server_stop_forced(server_pid)) then
568
+ @logger.fatal('failed to stop daemon.')
569
+ return 1
570
+ end
571
+ unless (@sysop.wait(server_pid)) then
572
+ @logger.fatal('failed to stop daemon.')
573
+ return 1
574
+ end
575
+ else
576
+ @logger.warn("internal warning: unknown stop state <#{@stop_state.inspect}>")
442
577
  end
443
578
  else
444
- @logger.error("internal error: unknown stop state <#{@stop_state.inspect}>")
445
- return 1
579
+ @logger.warn('no server to stop.')
580
+ end
581
+ ensure
582
+ server_socket_local_address = server_socket.local_address # get local_address before close(2)
583
+ if (@sysop.close(server_socket)) then
584
+ @logger.info("close server socket: #{server_socket_local_address.inspect_sockaddr}")
585
+ else
586
+ @logger.warn("failed to close server socket: #{server_socket_local_address.inspect_sockaddr}")
587
+ end
588
+ if (server_address.type == :unix) then
589
+ if (@sysop.unlink(server_address.path)) then
590
+ @logger.info("delete unix server socket: #{server_address}")
591
+ else
592
+ @logger.warn("failed to delete unix server socket: #{server_address}")
593
+ end
446
594
  end
447
- else
448
- @logger.warn('no server to stop.')
449
595
  end
450
596
 
451
597
  @logger.info('daemon stop.')
data/lib/riser/server.rb CHANGED
@@ -2,7 +2,6 @@
2
2
 
3
3
  require 'io/wait'
4
4
  require 'socket'
5
- require 'uri'
6
5
 
7
6
  module Riser
8
7
  class TimeoutSizedQueue
@@ -164,123 +163,6 @@ module Riser
164
163
  end
165
164
  end
166
165
 
167
- class SocketAddress
168
- def initialize(type)
169
- @type = type
170
- end
171
-
172
- attr_reader :type
173
-
174
- def to_a
175
- [ @type ]
176
- end
177
-
178
- def to_s
179
- to_a.map{|s|
180
- if (s.to_s.include? ':') then
181
- "[#{s}]"
182
- else
183
- s
184
- end
185
- }.join(':')
186
- end
187
-
188
- def ==(other)
189
- if (other.is_a? SocketAddress) then
190
- self.to_a == other.to_a
191
- else
192
- false
193
- end
194
- end
195
-
196
- def eql?(other)
197
- self == other
198
- end
199
-
200
- def hash
201
- to_a.hash ^ self.class.hash
202
- end
203
-
204
- def self.parse(config)
205
- unsquare = proc{|s| s.sub(/\A \[/x, '').sub(/\] \z/x, '') }
206
- case (config)
207
- when String
208
- case (config)
209
- when /\A tcp:/x
210
- uri = URI(config)
211
- if (uri.host && uri.port) then
212
- return TCPSocketAddress.new(unsquare.call(uri.host), uri.port)
213
- end
214
- when /\A unix:/x
215
- uri = URI(config)
216
- if (uri.path && ! uri.path.empty?) then
217
- return UNIXSocketAddress.new(uri.path)
218
- end
219
- when %r"\A [A-Za-z]+:/"x
220
- # unknown URI scheme
221
- when /\A (\S+):(\d+) \z/x
222
- host = $1
223
- port = $2.to_i
224
- return TCPSocketAddress.new(unsquare.call(host), port)
225
- end
226
- when Hash
227
- if (type = config[:type] || config['type']) then
228
- case (type.to_s)
229
- when 'tcp'
230
- host = config[:host] || config['host']
231
- port = config[:port] || config['port']
232
- if (host && (host.is_a? String) && port && (port.is_a? Integer)) then
233
- return TCPSocketAddress.new(unsquare.call(host), port)
234
- end
235
- when 'unix'
236
- path = config[:path] || config['path']
237
- if (path && (path.is_a? String) && ! path.empty?) then
238
- return UNIXSocketAddress.new(path)
239
- end
240
- end
241
- end
242
- end
243
-
244
- return
245
- end
246
- end
247
-
248
- class TCPSocketAddress < SocketAddress
249
- def initialize(host, port)
250
- super(:tcp)
251
- @host = host
252
- @port = port
253
- end
254
-
255
- attr_reader :host
256
- attr_reader :port
257
-
258
- def to_a
259
- super << @host << @port
260
- end
261
-
262
- def open_server
263
- TCPServer.new(@host, @port)
264
- end
265
- end
266
-
267
- class UNIXSocketAddress < SocketAddress
268
- def initialize(path)
269
- super(:unix)
270
- @path = path
271
- end
272
-
273
- attr_reader :path
274
-
275
- def to_a
276
- super << @path
277
- end
278
-
279
- def open_server
280
- UNIXServer.new(@path)
281
- end
282
- end
283
-
284
166
  module ServerSignal
285
167
  SIGNAL_STOP_GRACEFUL = :TERM
286
168
  SIGNAL_STOP_FORCED = :INT
@@ -417,6 +299,9 @@ module Riser
417
299
  # _server_socket is a dummy argument to call like
418
300
  # SocketProcessDispatcher#start.
419
301
  def start(_server_socket=nil)
302
+ error_lock = Mutex.new
303
+ last_error = nil
304
+
420
305
  @preprocess.call
421
306
  begin
422
307
  queue = TimeoutSizedQueue.new(@thread_queue_size, name: @thread_queue_name)
@@ -424,13 +309,19 @@ module Riser
424
309
  thread_list = []
425
310
  @thread_num.times{|i|
426
311
  thread_list << Thread.new{
427
- Thread.current[:number] = i
428
- while (socket = queue.pop)
429
- begin
430
- @dispatch.call(socket)
431
- ensure
432
- socket.close unless socket.closed?
312
+ begin
313
+ Thread.current[:number] = i
314
+ while (socket = queue.pop)
315
+ begin
316
+ @dispatch.call(socket)
317
+ ensure
318
+ socket.close unless socket.closed?
319
+ end
433
320
  end
321
+ rescue
322
+ error_lock.synchronize{
323
+ last_error = $!
324
+ }
434
325
  end
435
326
  }
436
327
  }
@@ -438,12 +329,14 @@ module Riser
438
329
  catch (:end_of_server) {
439
330
  while (true)
440
331
  begin
332
+ error_lock.synchronize{ last_error } and @stop_state = :forced
441
333
  @stop_state and throw(:end_of_server)
442
334
  apply_signal_stat(queue)
443
335
  socket = @accept.call
444
336
  end until (socket)
445
337
 
446
338
  until (queue.push(socket, @thread_queue_polling_timeout_seconds))
339
+ error_lock.synchronize{ last_error } and @stop_state = :forced
447
340
  if (@stop_state == :forced) then
448
341
  socket.close
449
342
  @accept_return.call
@@ -475,6 +368,12 @@ module Riser
475
368
  @postprocess.call
476
369
  end
477
370
 
371
+ error_lock.synchronize{
372
+ if (last_error) then
373
+ raise last_error
374
+ end
375
+ }
376
+
478
377
  nil
479
378
  end
480
379
  end
@@ -678,7 +577,11 @@ module Riser
678
577
 
679
578
  @process_dispatcher.accept{
680
579
  if (server_socket.wait_readable(@accept_polling_timeout_seconds) != nil) then
681
- server_socket.accept
580
+ begin
581
+ server_socket.accept_nonblock
582
+ rescue IO::WaitReadable
583
+ nil # to avoid conflicting accept(2) at server restart overlap
584
+ end
682
585
  end
683
586
  }
684
587
  @process_dispatcher.accept_return(&NO_CALL)
@@ -834,7 +737,11 @@ module Riser
834
737
  @dispatcher.postprocess(&@postprocess)
835
738
  @dispatcher.accept{
836
739
  if (server_socket.wait_readable(@accept_polling_timeout_seconds) != nil) then
837
- server_socket.accept
740
+ begin
741
+ server_socket.accept_nonblock
742
+ rescue IO::WaitReadable
743
+ nil # to avoid conflicting accept(2) at server restart overlap
744
+ end
838
745
  end
839
746
  }
840
747
  @dispatcher.accept_return(&NO_CALL)
@@ -0,0 +1,165 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'socket'
4
+ require 'uri'
5
+
6
+ module Riser
7
+ class SocketAddress
8
+ def initialize(type, backlog=nil)
9
+ @type = type
10
+ @backlog = backlog
11
+ end
12
+
13
+ attr_reader :type
14
+ attr_reader :backlog
15
+
16
+ def to_address
17
+ [ @type ]
18
+ end
19
+
20
+ def to_option
21
+ option = {}
22
+ option[:backlog] = @backlog if @backlog
23
+ option
24
+ end
25
+
26
+ def ==(other)
27
+ if (other.is_a? SocketAddress) then
28
+ [ self.to_address, self.to_option ] == [ other.to_address, other.to_option ]
29
+ else
30
+ false
31
+ end
32
+ end
33
+
34
+ def eql?(other)
35
+ self == other
36
+ end
37
+
38
+ def hash
39
+ [ to_address, to_option ].hash ^ self.class.hash
40
+ end
41
+
42
+ def self.parse(config)
43
+ unsquare = proc{|s| s.sub(/\A \[/x, '').sub(/\] \z/x, '') }
44
+ case (config)
45
+ when String
46
+ case (config)
47
+ when /\A tcp:/x
48
+ uri = URI(config)
49
+ if (uri.host && uri.port) then
50
+ return TCPSocketAddress.new(unsquare.call(uri.host), uri.port)
51
+ end
52
+ when /\A unix:/x
53
+ uri = URI(config)
54
+ if (uri.path && ! uri.path.empty?) then
55
+ return UNIXSocketAddress.new(uri.path)
56
+ end
57
+ when %r"\A [A-Za-z]+:/"x
58
+ # unknown URI scheme
59
+ when /\A (\S+):(\d+) \z/x
60
+ host = $1
61
+ port = $2.to_i
62
+ return TCPSocketAddress.new(unsquare.call(host), port)
63
+ end
64
+ when Hash
65
+ if (type = config[:type] || config['type']) then
66
+ case (type.to_s)
67
+ when 'tcp'
68
+ host = config[:host] || config['host']
69
+ port = config[:port] || config['port']
70
+ backlog = config[:backlog] || config['backlog']
71
+ if ((host && (host.is_a? String) && ! host.empty?) &&
72
+ (port && (port.is_a? Integer)) &&
73
+ (backlog.nil? || (backlog.is_a? Integer)))
74
+ then
75
+ return TCPSocketAddress.new(unsquare.call(host), port, backlog)
76
+ end
77
+ when 'unix'
78
+ path = config[:path] || config['path']
79
+ backlog = config[:backlog] || config['backlog']
80
+ mode = config[:mode] || config['mode']
81
+ owner = config[:owner] || config['owner']
82
+ group = config[:group] || config['group']
83
+ if ((path && (path.is_a? String) && ! path.empty?) &&
84
+ (backlog.nil? || (backlog.is_a? Integer)) &&
85
+ (mode.nil? || (mode.is_a? Integer)) &&
86
+ (owner.nil? || (owner.is_a? Integer) || ((owner.is_a? String) && ! owner.empty?)) &&
87
+ (group.nil? || (group.is_a? Integer) || ((group.is_a? String) && ! group.empty?)))
88
+ then
89
+ return UNIXSocketAddress.new(path, backlog, mode, owner, group)
90
+ end
91
+ end
92
+ end
93
+ end
94
+
95
+ return
96
+ end
97
+ end
98
+
99
+ class TCPSocketAddress < SocketAddress
100
+ def initialize(host, port, backlog=nil)
101
+ super(:tcp, backlog)
102
+ @host = host
103
+ @port = port
104
+ end
105
+
106
+ attr_reader :host
107
+ attr_reader :port
108
+
109
+ def to_address
110
+ super << @host << @port
111
+ end
112
+
113
+ def to_s
114
+ if (@host.include? ':') then
115
+ "tcp://[#{host}]:#{port}"
116
+ else
117
+ "tcp://#{host}:#{port}"
118
+ end
119
+ end
120
+
121
+ def open_server
122
+ TCPServer.new(@host, @port)
123
+ end
124
+ end
125
+
126
+ class UNIXSocketAddress < SocketAddress
127
+ def initialize(path, backlog=nil, mode=nil, owner=nil, group=nil)
128
+ super(:unix, backlog)
129
+ @path = path
130
+ @mode = mode
131
+ @owner = owner
132
+ @group = group
133
+ end
134
+
135
+ attr_reader :path
136
+ attr_reader :mode
137
+ attr_reader :owner
138
+ attr_reader :group
139
+
140
+ def to_address
141
+ super << @path
142
+ end
143
+
144
+ def to_option
145
+ option = super
146
+ option[:mode] = @mode if @mode
147
+ option[:owner] = @owner if @owner
148
+ option[:group] = @group if @group
149
+ option
150
+ end
151
+
152
+ def to_s
153
+ "unix:#{@path}"
154
+ end
155
+
156
+ def open_server
157
+ UNIXServer.new(@path)
158
+ end
159
+ end
160
+ end
161
+
162
+ # Local Variables:
163
+ # mode: Ruby
164
+ # indent-tabs-mode: nil
165
+ # End:
data/lib/riser/version.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
3
  module Riser
4
- VERSION = '0.1.1'
4
+ VERSION = '0.1.2'
5
5
  end
6
6
 
7
7
  # Local Variables:
data/lib/riser.rb CHANGED
@@ -13,7 +13,7 @@ module Riser
13
13
  autoload :ResourceSet, 'riser/resource'
14
14
  autoload :RootProcess, 'riser/daemon'
15
15
  autoload :ServerSignal, 'riser/server'
16
- autoload :SocketAddress, 'riser/server'
16
+ autoload :SocketAddress, 'riser/sockaddr'
17
17
  autoload :SocketServer, 'riser/server'
18
18
  autoload :StatusFile, 'riser/daemon'
19
19
  autoload :Stream, 'riser/stream'
data/riser.gemspec CHANGED
@@ -10,8 +10,11 @@ Gem::Specification.new do |spec|
10
10
  spec.authors = ["TOKI Yoshinori"]
11
11
  spec.email = ["toki@freedom.ne.jp"]
12
12
 
13
- spec.summary = %q{Riser}
14
- spec.description = %q{Riser is a library of Ruby Infrastructure for cooperative multi-thread/multi-process SERver.}
13
+ spec.summary = %q{Riser is a library of Ruby Infrastructure for cooperative multi-thread/multi-process SERver}
14
+ spec.description = <<-'EOF'
15
+ Riser is a library of Ruby Infrastructure for cooperative multi-thread/multi-process SERver.
16
+ This library is useful to make multi-thread/multi-process socket server and daemon.
17
+ EOF
15
18
  spec.homepage = "https://github.com/y10k/riser"
16
19
  spec.license = "MIT"
17
20
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: riser
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - TOKI Yoshinori
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-02-06 00:00:00.000000000 Z
11
+ date: 2019-02-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -66,8 +66,9 @@ dependencies:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
- description: Riser is a library of Ruby Infrastructure for cooperative multi-thread/multi-process
70
- SERver.
69
+ description: " Riser is a library of Ruby Infrastructure for cooperative multi-thread/multi-process
70
+ SERver.\n This library is useful to make multi-thread/multi-process socket server
71
+ and daemon. \n"
71
72
  email:
72
73
  - toki@freedom.ne.jp
73
74
  executables: []
@@ -98,6 +99,7 @@ files:
98
99
  - lib/riser/resource.rb
99
100
  - lib/riser/server.rb
100
101
  - lib/riser/services.rb
102
+ - lib/riser/sockaddr.rb
101
103
  - lib/riser/stream.rb
102
104
  - lib/riser/temppath.rb
103
105
  - lib/riser/test.rb
@@ -125,5 +127,6 @@ requirements: []
125
127
  rubygems_version: 3.0.1
126
128
  signing_key:
127
129
  specification_version: 4
128
- summary: Riser
130
+ summary: Riser is a library of Ruby Infrastructure for cooperative multi-thread/multi-process
131
+ SERver
129
132
  test_files: []