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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bd4f2d08b82c7340e6b00c8a97e63f66a6677fbc28e9b705ecb6c53d75701e00
4
- data.tar.gz: 11bc6d68d7837db49c123b5e2b08fc932bf60c1b0c29742e7e891e66d8f4f82a
3
+ metadata.gz: a1f6789411c7ea7ff1a641d74b0495b9d8e434d7ea5beaa4abbeade3e0cf2c33
4
+ data.tar.gz: 47ea5871588be9702620cd1487c2c05a5d314d70ff6e1a9df58456d3c6c1be53
5
5
  SHA512:
6
- metadata.gz: c29f7ea6b92d607774bef4f42dba2e03215f85078079fb3febd404cf87efff8f0536e03ba870234c72925f7404142dba2bf73217d7586175328d6611ba72e3d8
7
- data.tar.gz: 1b5d67e7165fb4c2ba1c667c774e089a5a5029e57ba47dd1f91cbcd17e2dcdef7136947b0d115d71b7db9c154013043f9da01428d55659898eee198bd1ca3d3a
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 & upload gem"
12
- task "package:release" do
13
- sh "git tag -s release-#{PACKAGE_VERSION}"
14
- sh "gem build #{PACKAGE_NAME}.gemspec"
15
- puts "Proceed with pushing tag to Github and uploading the gem? [y/n]"
16
- if $stdin.readline == "y\n"
17
- sh "git push origin release-#{PACKAGE_VERSION}"
18
- sh "gem push #{PACKAGE_NAME}-#{PACKAGE_VERSION}.gem"
19
- else
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
@@ -24,6 +24,6 @@
24
24
  class DaemonController
25
25
  MAJOR = 3
26
26
  MINOR = 0
27
- TINY = 0
27
+ TINY = 1
28
28
  VERSION_STRING = "#{MAJOR}.#{MINOR}.#{TINY}"
29
29
  end # class DaemonController
@@ -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: nil, logger: nil)
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
- if !daemon_is_running?
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
- begin
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.stat(@pid_file).size != 0
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
- if is_direct_child
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
- if is_direct_child
498
- begin
499
- debug "Waiting directly for process #{pid}"
500
- Process.waitpid(pid)
501
- rescue SystemCallError
502
- end
471
+ wait_for_aborted_process(pid:, is_direct_child:)
472
+ end
473
+ end
474
+ end
503
475
 
504
- # The daemon may have:
505
- # 1. Written a PID file before forking. We delete this PID file.
506
- # -OR-
507
- # 2. It might have forked (and written a PID file) right before
508
- # we terminated it. We'll want the fork to stay alive rather
509
- # than going through the (complicated) trouble of killing it.
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 || {}, ruby_interpreter, SPAWNER_FILE,
579
+ Process.spawn(@env, ruby_interpreter, SPAWNER_FILE,
602
580
  command, spawn_options)
603
581
  else
604
- Process.spawn(@env || {}, command, spawn_options)
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 ? File.read(tempfile_path).strip : nil)
596
+ return InternalCommandOkResult.new(pid, tempfile_path && File.read(tempfile_path).strip)
619
597
  rescue Timeout::Error
620
- return InternalCommandTimeoutResult.new(pid, tempfile_path ? File.read(tempfile_path).strip : nil)
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
- File.unlink(tempfile_path) if tempfile_path
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 !can_ping_unix_sockets?
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
- rb_config["bindir"],
788
- rb_config["RUBY_INSTALL_NAME"]
789
- ) + rb_config["EXEEXT"]
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.find { |name, n| n == num }[0])
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
- if output.nil? && logs.nil?
830
- result_inner = [
831
- "logs not available",
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
- "(#{result_inner})"
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
- result_inner = [
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
- result = ((output || "") + "\n" + (logs || "")).strip
845
- result_suffix = [
846
- exit_status ? signal_termination_message(exit_status) : nil,
847
- suffix_message
848
- ].compact.join("; ")
849
- if !result_suffix.empty?
850
- result << "\n(#{result_suffix})"
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
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "shellwords"
4
+ require "logger"
4
5
 
5
6
  root = File.absolute_path(File.join(File.dirname(__FILE__), ".."))
6
7
  Dir.chdir(root)
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.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: 2025-04-08 00:00:00.000000000 Z
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.2
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: []