Class: Nodectl::Process

Inherits:
Object
  • Object
show all
Defined in:
lib/nodectl/process.rb

Direct Known Subclasses

Action, Instance

Constant Summary collapse

ENV_BLACKLIST =
%w(BUNDLE_BIN_PATH BUNDLE_GEMFILE USE_BUNDLER _ORIGINAL_GEM_PATH _ RUBYOPT)
TIMEOUT =
10

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}, &blk) ⇒ Process

Returns a new instance of Process.



11
12
13
14
15
16
17
18
19
20
21
# File 'lib/nodectl/process.rb', line 11

def initialize(options = {}, &blk)
  raise "cannot create process without block" unless block_given?
  
  @status   = :pending
  @stopping = false
  @options  = options
  @blk      = blk
  @oncrash  = []
  @onstop   = []
  @onkill   = []
end

Instance Attribute Details

#exit_statusObject (readonly)

Returns the value of attribute exit_status.



9
10
11
# File 'lib/nodectl/process.rb', line 9

def exit_status
  @exit_status
end

#pidObject (readonly)

Returns the value of attribute pid.



7
8
9
# File 'lib/nodectl/process.rb', line 7

def pid
  @pid
end

#statusObject (readonly)

Returns the value of attribute status.



8
9
10
# File 'lib/nodectl/process.rb', line 8

def status
  @status
end

Instance Method Details

#alive?Boolean

Returns:

  • (Boolean)


45
46
47
48
49
50
51
# File 'lib/nodectl/process.rb', line 45

def alive?
  Process.getpgid(pid)
  true
rescue Errno::ESRCH
  dead!
  false
end

#dead!(exit_status = nil) ⇒ Object



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/nodectl/process.rb', line 77

def dead!(exit_status = nil)
  @detach.join

  if @detach.value
    @exit_status = @detach.value.exitstatus
  end

  if [:running, :stopping].include?(@status)
    case @status 
    when :stopping
      @status = :stopped
      Nodectl.logger.info("process: [#{pid}] stopped")
      onstop_call
    when :running
      @status = :crashed
      Nodectl.logger.info("process: [#{pid}] crashed")
      oncrash_call
    end

    onkill_call
    Nodectl::Process.delete(pid)
  end
end

#oncrash(&blk) ⇒ Object

When process crashed



102
103
104
# File 'lib/nodectl/process.rb', line 102

def oncrash(&blk)
  @oncrash << blk
end

#onkill(&blk) ⇒ Object

When process is dead, regardless of reason



112
113
114
# File 'lib/nodectl/process.rb', line 112

def onkill(&blk)
  @onkill << blk
end

#onstop(&blk) ⇒ Object

When process gracefully stoped



107
108
109
# File 'lib/nodectl/process.rb', line 107

def onstop(&blk)
  @onstop << blk
end

#restart(options = {}) ⇒ Object



64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/nodectl/process.rb', line 64

def restart(options = {})
  stop(options)
  TIMEOUT.times do
    unless alive?
      @status = :pending
      run
      break
    end

    sleep 1
  end
end

#runObject



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/nodectl/process.rb', line 23

def run
  if @status != :pending
    raise "Cannot run one process twice"
  end

  @pid = fork do
    ENV_BLACKLIST.each do |name|
      ENV.delete(name)
    end

    args = @options[:args] || []
    @blk.call(*args)

    EM.stop
  end

  @detach = Process.detach(@pid)

  @status = :running
  Nodectl::Process[pid] = self
end

#stop(options = {}) ⇒ Object



53
54
55
56
57
58
59
60
61
62
# File 'lib/nodectl/process.rb', line 53

def stop(options = {})
  @status = :stopping
  signal = options[:force] ? "KILL" : "TERM"

  Nodectl.logger.info("process: send #{signal} to #{pid}")

  Process.kill(signal, pid)
rescue Errno::ESRCH, Errno::EPERM
  dead!
end