riser 0.1.1 → 0.1.2

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 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: []