1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 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 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
| import threading import traceback import time import sys import os from functools import wraps
class WatchDog(threading.Thread):
def __init__(self, timeout=10, echo=False): super(WatchDog, self).__init__() self.timeout = timeout self.echo = echo self.last_kicked_ts = time.time() self.lock = threading.Lock() self.thread_id = threading.currentThread().ident self.terminated = False self.setDaemon(True) self.start()
def terminate(self): self.terminated = True self.join(self.timeout)
def kick(self): self.lock.acquire() self.last_kicked_ts = time.time() self.lock.release()
def bark(self): formated_frame_stack = self._get_formated_frame_stack() if self.echo: print("!!!!! WATCH DOG FAILURE TRIGGERED !!!!!\n" + formated_frame_stack, flush=True) pid = os.getpid() os.kill(pid, 2) time.sleep(5) os.kill(pid, 9)
def run(self): while not self.terminated: ts = time.time() self.lock.acquire() is_timeout = ts - self.last_kicked_ts > self.timeout self.lock.release() if is_timeout: self.bark() n = int(max(self.timeout / 3, 1)) for i in range(n*10): time.sleep(0.1) if self.terminated: break
@staticmethod def _get_thread(tid): for t in threading.enumerate(): if t.ident == tid: return t return None
@staticmethod def _get_frame_stack(tid): for thread_id, stack in sys._current_frames().items(): if thread_id == tid: return stack return None
def _get_formated_frame_stack(self): info = [] th = self._get_thread(self.thread_id) stack = self._get_frame_stack(self.thread_id) info.append('%s thead_id=%d' % (th.name, self.thread_id)) for filename, lineno, _, line in traceback.extract_stack(stack): info.append(' at %s(%s:%d)' % (line, filename[filename.rfind(os.path.sep) + 1:], lineno)) return '\n'.join(info)
def watch_dog(timeout=10, echo=False): def inner(func): def wrapper(*args, **kw): dog = WatchDog(timeout=timeout, echo=echo) ret = func(*args, **kw) dog.terminate() return ret return wrapper return inner
|