daemon_controller 3.0.0 → 3.0.1
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 +4 -4
- data/Rakefile +9 -11
- data/lib/daemon_controller/version.rb +1 -1
- data/lib/daemon_controller.rb +87 -123
- data/spec/test_helper.rb +1 -0
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a1f6789411c7ea7ff1a641d74b0495b9d8e434d7ea5beaa4abbeade3e0cf2c33
|
|
4
|
+
data.tar.gz: 47ea5871588be9702620cd1487c2c05a5d314d70ff6e1a9df58456d3c6c1be53
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bcecb7cd5d60e2a565e96d104085f2d09262336a1c3afcd583acff5d27f988bd617bb326aa0b5447d284e61cfd93d8ea8c42cf3d44ae918322b4167b17182681
|
|
7
|
+
data.tar.gz: 6fa2da44033e92a77a47ff0fdde71683e271f4115ddd7a5c5d2ef4a0904bcb65111f211564598ee7594ef97fe9b075918bfa3b76a4532f6fac131971d068448a
|
data/Rakefile
CHANGED
|
@@ -8,15 +8,13 @@ task :test do
|
|
|
8
8
|
ruby "-S rspec spec/*_spec.rb"
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
-
desc "Build
|
|
12
|
-
task
|
|
13
|
-
|
|
14
|
-
sh "gem build
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
puts "Did not upload the gem."
|
|
21
|
-
end
|
|
11
|
+
desc "Build gem"
|
|
12
|
+
task :gem do
|
|
13
|
+
mkdir_p "pkg"
|
|
14
|
+
sh "gem build daemon_controller.gemspec -o pkg/#{PACKAGE_NAME}-#{PACKAGE_VERSION}.gem"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
desc "Build release artifacts"
|
|
18
|
+
task release: :gem do
|
|
19
|
+
sh "gem push pkg/#{PACKAGE_NAME}-#{PACKAGE_VERSION}.gem"
|
|
22
20
|
end
|
data/lib/daemon_controller.rb
CHANGED
|
@@ -74,7 +74,7 @@ class DaemonController
|
|
|
74
74
|
lock_file: nil, stop_command: nil, restart_command: nil, before_start: nil,
|
|
75
75
|
start_timeout: 30, start_abort_timeout: 10, stop_timeout: 30,
|
|
76
76
|
log_file_activity_timeout: 10, ping_interval: 0.1, stop_graceful_signal: "TERM", dont_stop_if_pid_file_invalid: false,
|
|
77
|
-
daemonize_for_me: false, keep_ios: nil, env:
|
|
77
|
+
daemonize_for_me: false, keep_ios: nil, env: {}, logger: nil)
|
|
78
78
|
@identifier = identifier
|
|
79
79
|
@start_command = start_command
|
|
80
80
|
@ping_command = ping_command
|
|
@@ -140,7 +140,7 @@ class DaemonController
|
|
|
140
140
|
end
|
|
141
141
|
if connection.nil?
|
|
142
142
|
@lock_file.exclusive_lock do
|
|
143
|
-
|
|
143
|
+
unless daemon_is_running?
|
|
144
144
|
start_without_locking
|
|
145
145
|
end
|
|
146
146
|
connect_exception = nil
|
|
@@ -335,9 +335,7 @@ class DaemonController
|
|
|
335
335
|
|
|
336
336
|
def kill_daemon
|
|
337
337
|
if @stop_command
|
|
338
|
-
if @dont_stop_if_pid_file_invalid && read_pid_file.nil?
|
|
339
|
-
return
|
|
340
|
-
end
|
|
338
|
+
return if @dont_stop_if_pid_file_invalid && read_pid_file.nil?
|
|
341
339
|
|
|
342
340
|
result = run_command(@stop_command)
|
|
343
341
|
case result
|
|
@@ -356,8 +354,7 @@ class DaemonController
|
|
|
356
354
|
end
|
|
357
355
|
|
|
358
356
|
def kill_daemon_with_signal(force: false)
|
|
359
|
-
pid = read_pid_file
|
|
360
|
-
if pid
|
|
357
|
+
if (pid = read_pid_file)
|
|
361
358
|
if force
|
|
362
359
|
Process.kill("SIGKILL", pid)
|
|
363
360
|
else
|
|
@@ -380,14 +377,11 @@ class DaemonController
|
|
|
380
377
|
end
|
|
381
378
|
|
|
382
379
|
def read_pid_file
|
|
383
|
-
|
|
384
|
-
pid = File.read(@pid_file).strip
|
|
385
|
-
rescue Errno::ENOENT
|
|
386
|
-
return nil
|
|
387
|
-
end
|
|
380
|
+
pid = File.read(@pid_file).strip
|
|
388
381
|
if /\A\d+\Z/.match?(pid)
|
|
389
382
|
pid.to_i
|
|
390
383
|
end
|
|
384
|
+
rescue Errno::ENOENT
|
|
391
385
|
end
|
|
392
386
|
|
|
393
387
|
def delete_pid_file
|
|
@@ -438,7 +432,7 @@ class DaemonController
|
|
|
438
432
|
end
|
|
439
433
|
|
|
440
434
|
def pid_file_available?
|
|
441
|
-
File.exist?(@pid_file) && File.
|
|
435
|
+
File.exist?(@pid_file) && !File.zero?(@pid_file)
|
|
442
436
|
end
|
|
443
437
|
|
|
444
438
|
# This method does nothing and only serves as a hook for the unit test.
|
|
@@ -464,27 +458,7 @@ class DaemonController
|
|
|
464
458
|
begin
|
|
465
459
|
timeoutable(@start_abort_timeout) do
|
|
466
460
|
allow_timeout do
|
|
467
|
-
|
|
468
|
-
begin
|
|
469
|
-
debug "Waiting directly for process #{pid}"
|
|
470
|
-
Process.waitpid(pid)
|
|
471
|
-
rescue SystemCallError
|
|
472
|
-
end
|
|
473
|
-
|
|
474
|
-
# The daemon may have:
|
|
475
|
-
# 1. Written a PID file before forking. We delete this PID file.
|
|
476
|
-
# -OR-
|
|
477
|
-
# 2. It might have forked (and written a PID file) right before
|
|
478
|
-
# we terminated it. We'll want the fork to stay alive rather
|
|
479
|
-
# than going through the (complicated) trouble of killing it.
|
|
480
|
-
# Don't touch the PID file.
|
|
481
|
-
pid2 = read_pid_file
|
|
482
|
-
debug "PID file contains #{pid2.inspect}"
|
|
483
|
-
delete_pid_file if pid == pid2
|
|
484
|
-
else
|
|
485
|
-
debug "Waiting until daemon is no longer running"
|
|
486
|
-
wait_until { !daemon_is_running? }
|
|
487
|
-
end
|
|
461
|
+
wait_for_aborted_process(pid:, is_direct_child:)
|
|
488
462
|
end
|
|
489
463
|
end
|
|
490
464
|
rescue Timeout::Error
|
|
@@ -494,28 +468,32 @@ class DaemonController
|
|
|
494
468
|
end
|
|
495
469
|
|
|
496
470
|
allow_timeout do
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
rescue SystemCallError
|
|
502
|
-
end
|
|
471
|
+
wait_for_aborted_process(pid:, is_direct_child:)
|
|
472
|
+
end
|
|
473
|
+
end
|
|
474
|
+
end
|
|
503
475
|
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
# Don't touch the PID file.
|
|
511
|
-
pid2 = read_pid_file
|
|
512
|
-
debug "PID file contains #{pid2.inspect}"
|
|
513
|
-
delete_pid_file if pid == pid2
|
|
514
|
-
else
|
|
515
|
-
debug "Waiting until daemon is no longer running"
|
|
516
|
-
wait_until { !daemon_is_running? }
|
|
517
|
-
end
|
|
476
|
+
def wait_for_aborted_process(pid:, is_direct_child:)
|
|
477
|
+
if is_direct_child
|
|
478
|
+
begin
|
|
479
|
+
debug "Waiting directly for process #{pid}"
|
|
480
|
+
Process.waitpid(pid)
|
|
481
|
+
rescue SystemCallError
|
|
518
482
|
end
|
|
483
|
+
|
|
484
|
+
# The daemon may have:
|
|
485
|
+
# 1. Written a PID file before forking. We delete this PID file.
|
|
486
|
+
# -OR-
|
|
487
|
+
# 2. It might have forked (and written a PID file) right before
|
|
488
|
+
# we terminated it. We'll want the fork to stay alive rather
|
|
489
|
+
# than going through the (complicated) trouble of killing it.
|
|
490
|
+
# Don't touch the PID file.
|
|
491
|
+
pid2 = read_pid_file
|
|
492
|
+
debug "PID file contains #{pid2.inspect}"
|
|
493
|
+
delete_pid_file if pid == pid2
|
|
494
|
+
else
|
|
495
|
+
debug "Waiting until daemon is no longer running"
|
|
496
|
+
wait_until { !daemon_is_running? }
|
|
519
497
|
end
|
|
520
498
|
end
|
|
521
499
|
|
|
@@ -598,10 +576,10 @@ class DaemonController
|
|
|
598
576
|
end
|
|
599
577
|
|
|
600
578
|
pid = if @daemonize_for_me
|
|
601
|
-
Process.spawn(@env
|
|
579
|
+
Process.spawn(@env, ruby_interpreter, SPAWNER_FILE,
|
|
602
580
|
command, spawn_options)
|
|
603
581
|
else
|
|
604
|
-
Process.spawn(@env
|
|
582
|
+
Process.spawn(@env, command, spawn_options)
|
|
605
583
|
end
|
|
606
584
|
|
|
607
585
|
# run_command might be running in a timeout block (like
|
|
@@ -615,9 +593,9 @@ class DaemonController
|
|
|
615
593
|
# it started successfully; if it didn't we'll know
|
|
616
594
|
# that later by checking the PID file and by pinging
|
|
617
595
|
# it.
|
|
618
|
-
return InternalCommandOkResult.new(pid, tempfile_path
|
|
596
|
+
return InternalCommandOkResult.new(pid, tempfile_path && File.read(tempfile_path).strip)
|
|
619
597
|
rescue Timeout::Error
|
|
620
|
-
return InternalCommandTimeoutResult.new(pid, tempfile_path
|
|
598
|
+
return InternalCommandTimeoutResult.new(pid, tempfile_path && File.read(tempfile_path).strip)
|
|
621
599
|
end
|
|
622
600
|
|
|
623
601
|
child_status = $?
|
|
@@ -629,7 +607,7 @@ class DaemonController
|
|
|
629
607
|
end
|
|
630
608
|
ensure
|
|
631
609
|
begin
|
|
632
|
-
|
|
610
|
+
tempfile.unlink if tempfile
|
|
633
611
|
rescue SystemCallError
|
|
634
612
|
nil
|
|
635
613
|
end
|
|
@@ -706,43 +684,7 @@ class DaemonController
|
|
|
706
684
|
end
|
|
707
685
|
end
|
|
708
686
|
|
|
709
|
-
if
|
|
710
|
-
require "java"
|
|
711
|
-
|
|
712
|
-
def ping_socket(host_name, port)
|
|
713
|
-
channel = java.nio.channels.SocketChannel.open
|
|
714
|
-
begin
|
|
715
|
-
address = java.net.InetSocketAddress.new(host_name, port)
|
|
716
|
-
channel.configure_blocking(false)
|
|
717
|
-
if channel.connect(address)
|
|
718
|
-
return true
|
|
719
|
-
end
|
|
720
|
-
|
|
721
|
-
deadline = Time.now.to_f + 0.1
|
|
722
|
-
while true
|
|
723
|
-
begin
|
|
724
|
-
if channel.finish_connect
|
|
725
|
-
return true
|
|
726
|
-
end
|
|
727
|
-
rescue java.net.ConnectException => e
|
|
728
|
-
if /Connection refused/i.match?(e.message)
|
|
729
|
-
return false
|
|
730
|
-
else
|
|
731
|
-
throw e
|
|
732
|
-
end
|
|
733
|
-
end
|
|
734
|
-
|
|
735
|
-
# Not done connecting and no error.
|
|
736
|
-
sleep 0.01
|
|
737
|
-
if Time.now.to_f >= deadline
|
|
738
|
-
return false
|
|
739
|
-
end
|
|
740
|
-
end
|
|
741
|
-
ensure
|
|
742
|
-
channel.close
|
|
743
|
-
end
|
|
744
|
-
end
|
|
745
|
-
else
|
|
687
|
+
if can_ping_unix_sockets?
|
|
746
688
|
def ping_socket(socket_domain, sockaddr)
|
|
747
689
|
socket = Socket.new(socket_domain, Socket::Constants::SOCK_STREAM, 0)
|
|
748
690
|
begin
|
|
@@ -775,18 +717,43 @@ class DaemonController
|
|
|
775
717
|
rescue Errno::EAFNOSUPPORT
|
|
776
718
|
ping_socket(Socket::Constants::AF_INET6, sockaddr)
|
|
777
719
|
end
|
|
720
|
+
else
|
|
721
|
+
require "java"
|
|
722
|
+
|
|
723
|
+
def ping_socket(host_name, port)
|
|
724
|
+
channel = java.nio.channels.SocketChannel.open
|
|
725
|
+
begin
|
|
726
|
+
address = java.net.InetSocketAddress.new(host_name, port)
|
|
727
|
+
channel.configure_blocking(false)
|
|
728
|
+
return true if channel.connect(address)
|
|
729
|
+
|
|
730
|
+
deadline = Time.now.to_f + 0.1
|
|
731
|
+
loop do
|
|
732
|
+
begin
|
|
733
|
+
return true if channel.finish_connect
|
|
734
|
+
rescue java.net.ConnectException => e
|
|
735
|
+
if /Connection refused/i.match?(e.message)
|
|
736
|
+
return false
|
|
737
|
+
else
|
|
738
|
+
throw e
|
|
739
|
+
end
|
|
740
|
+
end
|
|
741
|
+
|
|
742
|
+
# Not done connecting and no error.
|
|
743
|
+
sleep 0.01
|
|
744
|
+
return false if Time.now.to_f >= deadline
|
|
745
|
+
end
|
|
746
|
+
ensure
|
|
747
|
+
channel.close
|
|
748
|
+
end
|
|
749
|
+
end
|
|
778
750
|
end
|
|
779
751
|
|
|
780
752
|
def ruby_interpreter
|
|
781
|
-
rb_config = if defined?(RbConfig)
|
|
782
|
-
RbConfig::CONFIG
|
|
783
|
-
else
|
|
784
|
-
Config::CONFIG
|
|
785
|
-
end
|
|
786
753
|
File.join(
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
)
|
|
754
|
+
RbConfig::CONFIG["bindir"],
|
|
755
|
+
RbConfig::CONFIG.values_at("RUBY_INSTALL_NAME", "EXEEXT").join
|
|
756
|
+
)
|
|
790
757
|
end
|
|
791
758
|
|
|
792
759
|
def timeoutable(amount, &block)
|
|
@@ -818,7 +785,7 @@ class DaemonController
|
|
|
818
785
|
end
|
|
819
786
|
|
|
820
787
|
def signal_name_for(num)
|
|
821
|
-
if (name = Signal.list.
|
|
788
|
+
if (name = Signal.list.key(num))
|
|
822
789
|
"SIG#{name}"
|
|
823
790
|
else
|
|
824
791
|
num.to_s
|
|
@@ -826,30 +793,27 @@ class DaemonController
|
|
|
826
793
|
end
|
|
827
794
|
|
|
828
795
|
def concat_spawn_output_and_logs(output, logs, exit_status = nil, suffix_message = nil)
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
796
|
+
format_full_suffix_message = lambda do |main_message = nil|
|
|
797
|
+
[
|
|
798
|
+
main_message,
|
|
832
799
|
exit_status ? signal_termination_message(exit_status) : nil,
|
|
833
800
|
suffix_message
|
|
834
801
|
].compact.join("; ")
|
|
835
|
-
|
|
802
|
+
end
|
|
803
|
+
|
|
804
|
+
if output.nil? && logs.nil?
|
|
805
|
+
"(#{format_full_suffix_message.call("logs not available")})"
|
|
836
806
|
elsif (output && output.empty? && logs && logs.empty?) || (output && output.empty? && logs.nil?) || (output.nil? && logs && logs.empty?)
|
|
837
|
-
|
|
838
|
-
"logs empty",
|
|
839
|
-
exit_status ? signal_termination_message(exit_status) : nil,
|
|
840
|
-
suffix_message
|
|
841
|
-
].compact.join("; ")
|
|
842
|
-
"(#{result_inner})"
|
|
807
|
+
"(#{format_full_suffix_message.call("logs empty")})"
|
|
843
808
|
else
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
809
|
+
full_suffix_message = format_full_suffix_message.call
|
|
810
|
+
if full_suffix_message.empty?
|
|
811
|
+
"#{output}\n#{logs}".strip
|
|
812
|
+
elsif logs && logs.empty?
|
|
813
|
+
"#{output}\n(#{full_suffix_message})".strip
|
|
814
|
+
else
|
|
815
|
+
"#{output}\n#{logs}\n(#{full_suffix_message})".strip
|
|
851
816
|
end
|
|
852
|
-
result
|
|
853
817
|
end
|
|
854
818
|
end
|
|
855
819
|
|
data/spec/test_helper.rb
CHANGED
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: daemon_controller
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.0.
|
|
4
|
+
version: 3.0.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Hongli Lai
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
11
|
dependencies: []
|
|
12
12
|
description: A library for robust daemon management.
|
|
13
13
|
email: software-signing@phusion.nl
|
|
@@ -46,7 +46,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
46
46
|
- !ruby/object:Gem::Version
|
|
47
47
|
version: '0'
|
|
48
48
|
requirements: []
|
|
49
|
-
rubygems_version: 3.6.
|
|
49
|
+
rubygems_version: 3.6.9
|
|
50
50
|
specification_version: 4
|
|
51
51
|
summary: A library for implementing daemon management capabilities
|
|
52
52
|
test_files: []
|