12

I would like to implement a simple watchdog timer in Python with two use cases:

  • Watchdog ensures that a function doesn't execute longer than x seconds
  • Watchdog ensures that certain regularly executed function does indeed execute at least every y seconds

How do I do that?

1

3 Answers 3

13

Just publishing my own solution to this:

from threading import Timer

class Watchdog(Exception):
    def __init__(self, timeout, userHandler=None):  # timeout in seconds
        self.timeout = timeout
        self.handler = userHandler if userHandler is not None else self.defaultHandler
        self.timer = Timer(self.timeout, self.handler)
        self.timer.start()

    def reset(self):
        self.timer.cancel()
        self.timer = Timer(self.timeout, self.handler)
        self.timer.start()

    def stop(self):
        self.timer.cancel()

    def defaultHandler(self):
        raise self

Usage if you want to make sure function finishes in less than x seconds:

watchdog = Watchdog(x)
try:
  # do something that might take too long
except Watchdog:
  # handle watchdog error
watchdog.stop()

Usage if you regularly execute something and want to make sure it is executed at least every y seconds:

import sys

def myHandler():
  print "Whoa! Watchdog expired. Holy heavens!"
  sys.exit()

watchdog = Watchdog(y, myHandler)

def doSomethingRegularly():
  # make sure you do not return in here or call watchdog.reset() before returning
  watchdog.reset()
Sign up to request clarification or add additional context in comments.

9 Comments

Ever heard of PEP8? And what is Timer() here?
Nope, haven't heard about it. I am beginner. But I will check once I have more time for this...
I'm not sure about your reset method. In your __init__ your Timer switches based on if userHandler (which should be is not None BTW) is supplied, in which case it's used. In reset - it's always self.handler that will then be used...
I think the __init__ function and reset function need to call self.timer.start().
This Watchdog raises the Exception (itself) in a separate thread (the Timer thread), so the try/except in the usage example is useless. The Watchdog also does not interrupt the long operation, which would be the point of a watchdog.
|
2

signal.alarm() sets a timeout for your program, and you can call it in your main loop, and set it to the greater of the two times you are prepared to tolerate:

import signal
while True:
    signal.alarm(10)
    infloop()

1 Comment

assuming that the interpreter runs on a platform which implements POSIX signals.
0

Here is a wdt I use in my app without class. It has no way to stop it:

from threading import Event, Thread

def wdt(time, callback):
    # a reset flag
    reset_e = Event()
    # a function to reset the wdt
    def reset(): reset_e.set()
    # the function to run in a differen thread
    def checker():
        # check if reset flag is set.
        # wait for specified time to give chance to reset.
        while reset_e.wait(time):
            # it was set in time. clear and wait again
            reset_e.clear()
        # time run out.
        callback()
    # the event is not set by default. Set it
    reset()
    # create and start the wdt
    t = Thread(target=checker)
    t.start()
    # return the resetter
    return reset


# The callback to run if wdt is not reset
def bark():
    print('woof')       

# Test
import time
reset = wdt(1.0, bark)
time.sleep(0.9)
reset()
time.sleep(2.0)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.