Class: ServerEngine::ProcessManager::Monitor

Inherits:
Object
  • Object
show all
Defined in:
lib/serverengine/process_manager.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(pid, opts = {}) ⇒ Monitor

Returns a new instance of Monitor.



289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
# File 'lib/serverengine/process_manager.rb', line 289

def initialize(pid, opts={})
  @pid = pid

  @enable_heartbeat = opts[:enable_heartbeat]
  @heartbeat_timeout = opts[:heartbeat_timeout]

  @graceful_kill_signal   = opts[:graceful_kill_signal]
  @graceful_kill_timeout  = opts[:graceful_kill_timeout]
  @graceful_kill_interval = opts[:graceful_kill_interval]
  @graceful_kill_interval_increment = opts[:graceful_kill_interval_increment]

  @immediate_kill_signal   = opts[:immediate_kill_signal]
  @immediate_kill_timeout  = opts[:immediate_kill_timeout]
  @immediate_kill_interval = opts[:immediate_kill_interval]
  @immediate_kill_interval_increment = opts[:immediate_kill_interval_increment]

  @error = false
  @last_heartbeat_time = Time.now
  @next_kill_time = nil
  @graceful_kill_start_time = nil
  @immediate_kill_start_time = nil
  @kill_count = 0

  @command_sender_pipe = nil
end

Instance Attribute Details

#command_sender_pipeObject

Returns the value of attribute command_sender_pipe.



315
316
317
# File 'lib/serverengine/process_manager.rb', line 315

def command_sender_pipe
  @command_sender_pipe
end

#last_heartbeat_timeObject

Returns the value of attribute last_heartbeat_time.



315
316
317
# File 'lib/serverengine/process_manager.rb', line 315

def last_heartbeat_time
  @last_heartbeat_time
end

#pidObject (readonly)

Returns the value of attribute pid.



316
317
318
# File 'lib/serverengine/process_manager.rb', line 316

def pid
  @pid
end

Instance Method Details

#heartbeat_delayObject



318
319
320
321
# File 'lib/serverengine/process_manager.rb', line 318

def heartbeat_delay
  now = Time.now
  now - @last_heartbeat_time
end

#joinObject



367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
# File 'lib/serverengine/process_manager.rb', line 367

def join
  pid = @pid
  return nil unless pid

  begin
    pid, status = Process.waitpid2(pid)
    code = status
  rescue #Errno::ECHILD, Errno::ESRCH, Errno::EPERM
    # assume that any errors mean the child process is dead
    code = $!
  end
  @pid = nil

  return code
end

#send_command(command) ⇒ Object



335
336
337
338
339
340
341
342
343
344
345
# File 'lib/serverengine/process_manager.rb', line 335

def send_command(command)
  pid = @pid
  return false unless pid

  begin
    @command_sender_pipe.write(command)
    return true
  rescue #Errno::EPIPE
    return false
  end
end

#send_signal(sig) ⇒ Object



323
324
325
326
327
328
329
330
331
332
333
# File 'lib/serverengine/process_manager.rb', line 323

def send_signal(sig)
  pid = @pid
  return nil unless pid

  begin
    Process.kill(sig, pid)
    return true
  rescue #Errno::ECHILD, Errno::ESRCH, Errno::EPERM
    return false
  end
end

#start_graceful_stop!Object



383
384
385
386
387
388
389
390
391
392
# File 'lib/serverengine/process_manager.rb', line 383

def start_graceful_stop!
  if ServerEngine.windows?
    # heartbeat isn't supported on Windows
    send_command("GRACEFUL_STOP\n")
  else
    now = Time.now
    @next_kill_time ||= now
    @graceful_kill_start_time ||= now
  end
end

#start_immediate_stop!Object



394
395
396
397
398
399
400
401
402
403
# File 'lib/serverengine/process_manager.rb', line 394

def start_immediate_stop!
  if ServerEngine.windows?
    # heartbeat isn't supported on Windows
    system("taskkill /f /pid #{@pid}")
  else
    now = Time.now
    @next_kill_time ||= now
    @immediate_kill_start_time ||= now
  end
end

#tick(now = Time.now) ⇒ Object



405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
# File 'lib/serverengine/process_manager.rb', line 405

def tick(now=Time.now)
  pid = @pid
  return false unless pid

  if !@immediate_kill_start_time
    # check heartbeat timeout or escalation
    if (
        # heartbeat timeout
        @enable_heartbeat &&
        heartbeat_delay >= @heartbeat_timeout
       ) || (
         # escalation
         @graceful_kill_start_time &&
         @graceful_kill_timeout >= 0 &&
         @graceful_kill_start_time < now - @graceful_kill_timeout
       )
      # escalate to immediate kill
      @kill_count = 0
      @immediate_kill_start_time = now
      @next_kill_time = now
    end
  end

  if !@next_kill_time || @next_kill_time > now
    # expect next tick
    return true
  end

  # send signal now

  if @immediate_kill_start_time
    interval = @immediate_kill_interval
    interval_incr = @immediate_kill_interval_increment
    if @immediate_kill_timeout >= 0 &&
        @immediate_kill_start_time <= now - @immediate_kill_timeout
      # escalate to SIGKILL
      signal = :KILL
    else
      signal = @immediate_kill_signal
    end

  else
    signal = @graceful_kill_signal
    interval = @graceful_kill_interval
    interval_incr = @graceful_kill_interval_increment
  end

  begin
    if ServerEngine.windows? && (signal == :KILL || signal == :SIGKILL)
      system("taskkill /f /pid #{pid}")
    else
      Process.kill(signal, pid)
    end
  rescue #Errno::ECHILD, Errno::ESRCH, Errno::EPERM
    # assume that any errors mean the child process is dead
    @pid = nil
    return false
  end

  @next_kill_time = now + interval + interval_incr * @kill_count
  @kill_count += 1

  # expect next tick
  return true
end

#try_joinObject



347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
# File 'lib/serverengine/process_manager.rb', line 347

def try_join
  pid = @pid
  return true unless pid

  begin
    pid, status = Process.waitpid2(pid, Process::WNOHANG)
    code = status
  rescue #Errno::ECHILD, Errno::ESRCH, Errno::EPERM
    # assume that any errors mean the child process is dead
    code = $!
  end

  if code
    @pid = nil
    return code
  end

  return false
end