Skip to content

Instantly share code, notes, and snippets.

@furushchev
Last active December 23, 2017 04:12
Show Gist options
  • Save furushchev/7cb528bdabf650bd067e26685c903a4c to your computer and use it in GitHub Desktop.
Save furushchev/7cb528bdabf650bd067e26685c903a4c to your computer and use it in GitHub Desktop.
This is just a wrapper for command line but monitors rosmaster and respawn automatically
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Author: furushchev <[email protected]>
import os
import rosgraph
import rospy
import signal
import subprocess
import sys
import time
from threading import Event, Lock, Thread
IS_POSIX = 'posix' in sys.builtin_module_names
TIMEOUT_SIGINT = 10.0
TIMEOUT_SIGTERM = 2.0
def logout(fmt, **args):
print "\x1b[32m" + fmt % args + '\x1b[39m'
class ROSMasterWatchdog(Thread):
def __init__(self, rate):
super(ROSMasterWatchdog, self).__init__()
self.rate = rate
self.event = Event()
self.lock = Lock()
self.alive = True
def stop(self):
self.event.set()
def get(self):
with self.lock:
return self.alive
def run(self):
while not self.event.wait(self.rate):
with self.lock:
self.alive = rosgraph.is_master_online()
proc = None
args = rospy.myargv()[1:]
def signal_handler(signum, stack):
global proc
if proc and proc.poll() is None:
proc.send_signal(signum)
logout("Sent signal %d to application" % signum)
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)
signal.signal(signal.SIGHUP, signal_handler)
watchdog = ROSMasterWatchdog(1.0)
watchdog.start()
def kill_process(p):
if p is None:
return 0
if p.poll() is not None:
return p.poll()
try:
p.send_signal(signal.SIGINT)
timeout = time.time() + TIMEOUT_SIGINT
while time.time() < timeout:
if p.poll() is not None:
return p.poll()
time.sleep(0.1)
logout("escalated to SIGTERM")
p.send_signal(signal.SIGTERM)
timeout = time.time() + TIMEOUT_SIGTERM
while time.time() < timeout:
if p.poll() is not None:
return p.poll()
time.sleep(0.1)
logout("escalated to SIGKILL")
p.kill()
p.wait()
except Exception as e:
logout("Failed to kill process: %s" % str(e))
return p.poll()
while True:
time.sleep(1)
master = watchdog.get()
if proc and (not master):
logout("Master is no more alive. Killing the application")
kill_process(proc)
proc = None
elif proc is None and master:
logout("Master is alive. Starting the application.")
proc = subprocess.Popen(
args, close_fds=IS_POSIX,
env=os.environ.copy(),
preexec_fn=os.setpgrp(),
)
if proc and proc.poll() is not None:
logout("Child process exited with %d" % proc.poll())
break
if watchdog:
watchdog.stop()
watchdog.join()
sys.exit(kill_process(proc))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment