david-mccullars/safe_timeout

View on GitHub
lib/safe_timeout/spawner.rb

Summary

Maintainability
A
0 mins
Test Coverage
A
100%
require 'English'
module SafeTimeout
  class Spawner

    def initialize(options = {})
      @expiration = Time.now.to_f + options.fetch(:timeout)
      @on_timeout = lambda do |*args|
        @timed_out = true
        options.fetch(:on_timeout).call(*args)
      end
      @timed_out = false
    end

    def start
      original = Signal.trap('TRAP', &@on_timeout) || 'DEFAULT'
      spawn_interrupter
      yield
    ensure
      Signal.trap('TRAP', original)
      stop
    end

    def stop
      # Tell that child to stop interrupting!
      SafeTimeout.send_signal('HUP', @child_pid) unless @timed_out
      Process.wait(@child_pid) rescue nil
    end

    def spawn_interrupter
      # Create a light-weight child process to notify this process if it is
      # taking too long
      bin = Gem.bin_path('safe_timeout', 'safe_timeout')
      @child_pid = Process.spawn({ 'COVERAGE' => defined?(SimpleCov) }, bin, @expiration.to_s)
      Process.detach(@child_pid)
    end

  end
end