Search code examples
pythonserver-sent-events

Restart a python function in a script after n minutes


I have a script that uses a server-sent event library to connect with a server that pushes events to me regularly. The issue is that the stream will freeze after a long time and I will have to restart the script manually and this is not maintainable. The structure of the current code looks like this

def listen(self):
        print("listening to events .....")
        try:
            url = settings.EVENT_URL + "/v1/events"
            auth_key = settings.KEY

            headers = {
                "Authorization": "Basic " + auth_key,
                "Accept": "text/event-stream",
            }

            response = self.with_urllib3(url, headers)
            client = sseclient.SSEClient(response)

            for event in client.events():
                # the script freezes here.
                logger.info(event.data)

                process(event.data)

I have tried doing something like

def start(self):
    def wait():
        time.sleep(10 * 60)

    background = threading.Thread(name = 'background', target = self.listen)
    background.daemon = True
    background.start()
    wait()

try:
    self.start()
except:
    self.start()
finally:
    self.start()

But I don't know if this will work mainly because a daemon thread will keep running in the background which means I will have copies of the task running after a while.

What I need is a better way to call a function and after some elapsed time return from the function and recall it again immediately. Thanks for any help.


Solution

  • You could consider a construction using the signal module like shown below. As a note though, the SIGALRM signal is not compatible with Windows.

    import signal
    
    
    TIMEOUT = 5
    
    
    def _handle_alarm(_, __):
        raise TimeoutError("Some useful message")
    
    
    def listen():
        print("Starting to listen...")
        import time
        time.sleep(10)
    
    
    while True:
        try:
            timer = signal.signal(signal.SIGALRM, _handle_alarm)
            timer.alarm(TIMEOUT)
            listen()
        except TimeoutError:
            pass