Python Run Two Functions With Different Timers In One Daemon

1.5k views Asked by At

I'm using the template python daemon discussed here in two different scripts to launch two separate daemons. I would like to combine them into one daemon script that has one lockfile, etc. However, each has different loop timer, one at 1 minute and the other at 5 minutes. I'm starting with this:

import os
import subprocess
import time
from daemon import runner

class App():
    def __init__(self):
        self.stdin_path = '/dev/null'
        self.stdout_path = '/dev/tty'
        self.stderr_path = '/dev/tty'
        self.pidfile_path =  '/tmp/test.pid'
        self.pidfile_timeout = 5
    def run(self):

        try:
            while True:

                print "hello!"

                # set the sleep time for repeated action here:
                time.sleep(1)

        except Exception, e:
            raise


app = App()
daemon_runner = runner.DaemonRunner(app)
daemon_runner.do_action()

The obvious thing to do would be to create another class but I want the basic stuff like pidfile to remain constant.

2

There are 2 answers

0
Danica On BEST ANSWER

I'm don't entirely get why you want to do this, but this should work:

Make run_A and run_B functions to do the two independent things (obviously not those names), including the sleeps and so on. It doesn't really matter, but it might make sense to have these outside the App class.

Then make a run function that looks like this:

def run(self):
    threads = [
         threading.Thread(target=run_A),
         threading.Thread(target=run_B)
    ]

    for thread in threads:
         thread.start()
    for thread in threads:
         thread.join()

This will spawn a separate thread for each job, which can then go on its merry way. If you have any shared resources between the jobs, you'll have to worry about locking.

This assumes that the jobs are quick to execute and exact timings don't really matter; because of CPython's GIL, only one thread will run Python statements at once, so if they pop up at the same time they'll run a bit slower. You could pretty trivially switch this to use multiprocessing if you want them to be able to run in parallel.

This will result in some "timer drift" because you're using sleep (as would your daemons if run independently). If this matters, you could use interrupts instead, or calculate the time until the next multiple of five minutes rather than just sleeping five minutes.

0
Blckknght On

If it isn't essential for your longer delay to execute exactly on time, you can use a simple accumulator to keep track of how much time has been used by several cycles of the shorter action. The code below, will work perfectly if LONG_DELAY is an exact integer multiple of SHORT_DELAY. If it is not an exact multiple, the longer cycle will still execute with the requested period on average, but the delay may be shorter or longer by up to SHORT_DELAY on any given pass:

SHORT_DELAY = 60 # 1 minute
LONG_DELAY = 300 # 5 minutes

accum = LONG_DELAY

while True:
    do_short_delay_action()

    if accum >= LONG_DELAY:
        do_long_delay_action()
        accum -= LONG_DELAY

    time.sleep(SHORT_DELAY)
    accum += SHORT_DELAY