Class: Erlnixify::Node

Inherits:
Object
  • Object
show all
Defined in:
lib/erlnixify/node.rb

Overview

The process class owns the Running erlang process. It knows how to query it if its active, and kill it if something goes long. This class is the guts of erlnixify

Instance Method Summary collapse

Constructor Details

#initialize(settings) ⇒ Node

Returns a new instance of Node.



17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/erlnixify/node.rb', line 17

def initialize(settings)
  @settings = settings
  @command = @settings[:command] % settings.settings
  @check_command = self.interpolate_cmd(@settings[:check])
  @halt_command = self.interpolate_cmd(SHUTDOWN_COMMAND)
  @brutal_halt_command = self.interpolate_cmd(BRUTAL_SHUTDOWN_COMMAND)
  @checkregex = Regexp.new @settings[:checkregex]

  @log = Logger.new(STDOUT)
  @log.level = Logger::DEBUG

end

Instance Method Details

#checkObject



98
99
100
101
102
103
104
105
106
107
# File 'lib/erlnixify/node.rb', line 98

def check
  begin
    Timeout.timeout(@settings[:checktimeout]) do
      self.raw_check
    end
  rescue Timeout::Error
    self.halt_nicely
    raise NodeError, "Check command timeout occurred"
  end
end

#external_killObject



175
176
177
178
179
180
# File 'lib/erlnixify/node.rb', line 175

def external_kill
  if self.is_running?
    @log.debug "Killing pid: #{@pid}"
    Process.kill("KILL", @pid) if @pid
  end
end

#halt_brutallyObject



166
167
168
169
170
171
172
173
# File 'lib/erlnixify/node.rb', line 166

def halt_brutally
  if self.is_running?
    @log.debug "Executing halt brutally: #{@brutal_halt_command}"
    `#{@brutal_halt_command}`
    sleep @settings[:checkinterval]
    self.external_kill
  end
end

#halt_nicelyObject



157
158
159
160
161
162
163
164
# File 'lib/erlnixify/node.rb', line 157

def halt_nicely
  if self.is_running?
    @log.debug "Executing halt nicely: #{@halt_command}"
    `#{@halt_command}`
    sleep @settings[:checkinterval]
    self.halt_brutally
  end
end

#interpolate_cmd(cmd) ⇒ Object



182
183
184
185
186
# File 'lib/erlnixify/node.rb', line 182

def interpolate_cmd(cmd)
  local_settings = @settings.settings.clone
  local_settings[:cmd] = cmd % local_settings
  COMMAND_WRAPPER % local_settings
end

#is_running?Boolean

Returns:

  • (Boolean)


133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/erlnixify/node.rb', line 133

def is_running?
  @log.debug "Checking if Pid (#{@pid}) is running"
  if @pid
    begin
      Process.getpgid(@pid)
      true
    rescue Errno::ESRCH
      false
    end
  else
    false
  end
end

#monitorObject



84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/erlnixify/node.rb', line 84

def monitor
  @log.debug "starting monitor of Pid #{@pid}"
  loop do
    if is_running?
      self.check
      sleep @settings[:checkinterval]
    else
      raise NodeError, "Node not running"
    end
    break if @stop
    @log.debug "Node responded correctly, continuing check"
  end
end

#raw_checkObject



120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/erlnixify/node.rb', line 120

def raw_check
  @log.debug "#{@check_command} =~ #{@checkregex}"
  result = `#{@check_command}`
  @log.debug "result #{result}"
  if not (result =~ @checkregex)
    @log.info "invalid state"
    self.halt_nicely
    raise NodeError, "Node check failed"
  else
    @log.info "running"
  end
end

#raw_start_daemonObject



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/erlnixify/node.rb', line 65

def raw_start_daemon
  @log.debug "starting daemon"
  env = {}
  env["HOME"] = @settings[:home] if @settings[:home]

  begin
    @log.debug "spawning command '#{@command}' with #{env}"
    @pid = Process.spawn(env, @command)
    Process.detach @pid
  rescue Errno::ENOENT
    @log.debug "Invalid command provided, raising error"
    raise NodeError, "Command does not exist"
  end

  @log.debug "waiting for #{@settings[:startuptimeout]} seconds for startup"
  sleep @settings[:startuptimeout]
  self.status
end

#startObject



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/erlnixify/node.rb', line 30

def start
  self.start_daemon

  Signal.trap("TERM") do
    # This is going to propagate to the running erlang
    # node. Unfortunately, there is no way to stop that that I
    # have found yet. Hopefully, in the near future we can resolve
    # that.
    raise NodeError, "SIGTERM recieved, shutting down"
  end

  Signal.trap("INT") do
    # This is going to propagate to the running erlang
    # node. Unfortunately, there is no way to stop that that I
    # have found yet. Hopefully, in the near future we can resolve
    # that.
    raise NodeError, "SIGINT recieved, shutting down"
  end

  at_exit { self.external_kill }

  @log.debug "waiting for #{@settings[:startuptimeout]} seconds for startup"
  sleep @settings[:startuptimeout]
  self.monitor
end

#start_daemonObject

Raises:



56
57
58
59
60
61
62
63
# File 'lib/erlnixify/node.rb', line 56

def start_daemon
  begin
    self.status
  rescue NodeError => msg
    return self.raw_start_daemon
  end
  raise NodeError, "Already started"
end

#statusObject



109
110
111
112
113
114
115
116
117
118
# File 'lib/erlnixify/node.rb', line 109

def status
  begin
    Timeout.timeout(@settings[:checktimeout]) do
        self.raw_check
    end
  rescue Timeout::Error
    self.halt_nicely
    raise NodeError, "Check command timeout occurred"
  end
end

#stopObject



147
148
149
150
151
152
153
154
155
# File 'lib/erlnixify/node.rb', line 147

def stop
  @log.debug "Executing halt nicely: #{@halt_command}"
  `#{@halt_command}`
  if not $?
    sleep @settings[:checkinterval]
  else
    raise NodeError, "Got status #{$?}"
  end
end