Module: WifiWand::ProcessProbeManager
- Included in:
- CaptivePortalChecker, NetworkConnectivityTester
- Defined in:
- lib/wifi_wand/services/process_probe_manager.rb
Instance Method Summary collapse
-
#finalize_probe(probe, grace: helper_result_grace) ⇒ Object
Finalizes a successful probe that has produced a result.
- #helper_exit_poll_interval ⇒ Object
- #helper_result_grace ⇒ Object
- #probe_reaped_within_grace?(pid, grace:) ⇒ Boolean
- #reap_probe(pid) ⇒ Object
-
#terminate_probe(probe, grace: helper_result_grace) ⇒ Object
Forces termination of a probe process.
- #terminate_probes(probes, grace: helper_result_grace) ⇒ Object
- #wait_for_killed_probe_reap(pid) ⇒ Object
- #wait_for_probe_exit(pid, grace: helper_result_grace) ⇒ Object
Instance Method Details
#finalize_probe(probe, grace: helper_result_grace) ⇒ Object
Finalizes a successful probe that has produced a result. Unlike terminate_probe, this first waits for the helper to exit on its own before attempting termination. This is the standard path for helpers that have finished their work and are expected to exit promptly.
40 41 42 43 44 45 46 47 48 49 50 51 52 |
# File 'lib/wifi_wand/services/process_probe_manager.rb', line 40 def finalize_probe(probe, grace: helper_result_grace) pid = probe[:pid] probe[:reader]&.close unless probe[:reader]&.closed? return unless pid # Wait briefly for helper exit before clearing the PID. if probe_reaped_within_grace?(pid, grace: grace) probe[:pid] = nil else # Helper produced a result but is still running; escalate cleanup. terminate_probe(probe, grace: grace) end end |
#helper_exit_poll_interval ⇒ Object
12 13 14 |
# File 'lib/wifi_wand/services/process_probe_manager.rb', line 12 def helper_exit_poll_interval 0.01 end |
#helper_result_grace ⇒ Object
5 6 7 8 9 10 |
# File 'lib/wifi_wand/services/process_probe_manager.rb', line 5 def helper_result_grace return self.class::HELPER_RESULT_GRACE if self.class.const_defined?(:HELPER_RESULT_GRACE, false) raise NotImplementedError, "#{self.class} must define HELPER_RESULT_GRACE to include ProcessProbeManager" end |
#probe_reaped_within_grace?(pid, grace:) ⇒ Boolean
72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/wifi_wand/services/process_probe_manager.rb', line 72 def probe_reaped_within_grace?(pid, grace:) deadline = Process.clock_gettime(Process::CLOCK_MONOTONIC) + grace loop do return true if reap_probe(pid) remaining = deadline - Process.clock_gettime(Process::CLOCK_MONOTONIC) break if remaining <= 0 sleep([helper_exit_poll_interval, remaining].min) end false end |
#reap_probe(pid) ⇒ Object
54 55 56 57 58 59 60 |
# File 'lib/wifi_wand/services/process_probe_manager.rb', line 54 def reap_probe(pid) return unless pid Process.wait(pid, Process::WNOHANG) || nil rescue Errno::ECHILD nil end |
#terminate_probe(probe, grace: helper_result_grace) ⇒ Object
Forces termination of a probe process. Sends SIGTERM, waits for grace, then escalates to SIGKILL if necessary. Always ensures the reader pipe is closed and the PID is cleared from the probe hash.
23 24 25 26 27 28 29 30 31 32 33 34 |
# File 'lib/wifi_wand/services/process_probe_manager.rb', line 23 def terminate_probe(probe, grace: helper_result_grace) pid = probe[:pid] probe[:reader]&.close unless probe[:reader]&.closed? return unless pid Process.kill('TERM', pid) wait_for_probe_exit(pid, grace: grace) probe[:pid] = nil rescue Errno::ESRCH, Errno::ECHILD probe[:pid] = nil nil end |
#terminate_probes(probes, grace: helper_result_grace) ⇒ Object
16 17 18 |
# File 'lib/wifi_wand/services/process_probe_manager.rb', line 16 def terminate_probes(probes, grace: helper_result_grace) probes.each { |probe| terminate_probe(probe, grace: grace) } end |
#wait_for_killed_probe_reap(pid) ⇒ Object
87 88 89 90 91 92 |
# File 'lib/wifi_wand/services/process_probe_manager.rb', line 87 def wait_for_killed_probe_reap(pid) Process.wait(pid) true rescue Errno::ECHILD true end |
#wait_for_probe_exit(pid, grace: helper_result_grace) ⇒ Object
62 63 64 65 66 67 68 69 70 |
# File 'lib/wifi_wand/services/process_probe_manager.rb', line 62 def wait_for_probe_exit(pid, grace: helper_result_grace) return true if probe_reaped_within_grace?(pid, grace: grace) # Escalation: SIGKILL after grace period expired Process.kill('KILL', pid) wait_for_killed_probe_reap(pid) rescue Errno::ESRCH, Errno::ECHILD true end |