Class: Rundoc::CodeCommand::Background::ProcessSpawn

Inherits:
Object
  • Object
show all
Defined in:
lib/rundoc/code_command/background/process_spawn.rb

Overview

This class is responsible for running processes in the background

By default it logs output to a file. This can be used to “wait” for a specific output before continuing:

server = ProcessSpawn("rails server")
server.wait("Use Ctrl-C to stop")

The process can be queried for it’s status to check if it is still booted or not. the process can also be manually stopped:

server = ProcessSpawn("rails server")
server.alive? # => true
server.stop
server.alive? # => false

There are class level methods that can be used to “name” and record background processes. They can be used like this:

server = ProcessSpawn("rails server")
ProcessSpawn.add("muh_server", server)
ProcessSpawn.find("muh_server") # => <# ProcessSpawn instance >
ProcessSpawn.find("foo") # => RuntimeError "Could not find task with name 'foo', ..."

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(command, timeout: 5, log: Tempfile.new("log"), out: "2>&1") ⇒ ProcessSpawn

Returns a new instance of ProcessSpawn.



48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/rundoc/code_command/background/process_spawn.rb', line 48

def initialize(command, timeout: 5, log: Tempfile.new("log"), out: "2>&1")
  @command = command
  @timeout_value = timeout
  @log_reference = log # https://twitter.com/schneems/status/1285289971083907075

  @log = Pathname.new(log)
  @log.dirname.mkpath
  FileUtils.touch(@log)

  @command = "/usr/bin/env bash -c #{@command.shellescape} >> #{@log} #{out}"
  @pid = nil
end

Class Attribute Details

.tasksObject (readonly)

Returns the value of attribute tasks.



32
33
34
# File 'lib/rundoc/code_command/background/process_spawn.rb', line 32

def tasks
  @tasks
end

Instance Attribute Details

#logObject (readonly)

Returns the value of attribute log.



46
47
48
# File 'lib/rundoc/code_command/background/process_spawn.rb', line 46

def log
  @log
end

#pidObject (readonly)

Returns the value of attribute pid.



46
47
48
# File 'lib/rundoc/code_command/background/process_spawn.rb', line 46

def pid
  @pid
end

Class Method Details

.add(name, value) ⇒ Object



36
37
38
39
# File 'lib/rundoc/code_command/background/process_spawn.rb', line 36

def self.add(name, value)
  raise "Task named #{name.inspect} is already started, choose a different name" if @tasks[name]
  @tasks[name] = value
end

.find(name) ⇒ Object



41
42
43
44
# File 'lib/rundoc/code_command/background/process_spawn.rb', line 41

def self.find(name)
  raise "Could not find task with name #{name.inspect}, known task names: #{@tasks.keys.inspect}" unless @tasks[name]
  @tasks[name]
end

Instance Method Details

#alive?Boolean

Returns:

  • (Boolean)


74
75
76
77
78
79
# File 'lib/rundoc/code_command/background/process_spawn.rb', line 74

def alive?
  return false unless @pid
  Process.kill(0, @pid)
rescue Errno::ESRCH, Errno::EPERM
  false
end

#check_alive!Object



87
88
89
# File 'lib/rundoc/code_command/background/process_spawn.rb', line 87

def check_alive!
  raise "#{@original_command} has exited unexpectedly: #{@log.read}" unless alive?
end

#stopObject



81
82
83
84
85
# File 'lib/rundoc/code_command/background/process_spawn.rb', line 81

def stop
  return unless alive?
  Process.kill("TERM", -Process.getpgid(@pid))
  Process.wait(@pid)
end

#wait(wait_value = nil, timeout_value = @timeout_value) ⇒ Object



61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/rundoc/code_command/background/process_spawn.rb', line 61

def wait(wait_value = nil, timeout_value = @timeout_value)
  call
  return unless wait_value

  Timeout.timeout(Integer(timeout_value)) do
    until @log.read.match(wait_value)
      sleep 0.01
    end
  end
rescue Timeout::Error
  raise "Timeout waiting for #{@command.inspect} to find a match using #{wait_value.inspect} in \n'#{log.read}'"
end