Retry a code if runs indefinitely in Python

85 Views Asked by At

I am trying to run a code which tries to fetch data from an API:

client.quotes(instrument_tokens=inst_tokens, quote_type="", isIndex=False)

However, sometimes this code keeps running indefinitely without returning any data and I need to interrupt the code using the keyboard and run my code again. I would like to handle this in my code wherein if it takes more than 10 seconds to fetch the data, I retry fetching this data after say, 10 seconds. I have tried using threading, something like

while True:
    thread = threading.Thread(target=run_with_timeout(inst_tokens))
    thread.start()
    thread.join(timeout=10)
    if thread.is_alive():
        print("Execution of quote API took more than 10 seconds. Retrying in 15 seconds...", str(datetime.datetime.now()))
        thread.join()  # Ensure the thread is terminated before retrying
        time.sleep(retry_delay)  # Wait before retrying
        continue  # Restart the loop
    break  # Exit the loop if code ran within time limit

where run_with_timeout is essentially the client.quotes function. Yet this doesn't seem to work and my code still gets stuck running indefinitely. Can anyone please help me with this issue.

2

There are 2 best solutions below

0
Nanomachines_Son On

Maybe you should use requests module for handling api requests. It has a built-in get() which has a timeout parameter which stops an indefinite loop after the given time has elapsed.

2
SIGHUP On

You could use an alarm. Then you wouldn't need a thread.

Something like this:

from time import sleep
from signal import signal, SIGALRM, alarm

TIMEOUT = 2
SLEEP = 5
MAXRETRIES = 5

class Timeout(Exception):
    ...

def run_with_timeout(inst_tokens):
    def _handler(*_):
        raise Timeout

    # don't know what client is so just make something up
    class Client:
        def quotes(self, instrument_tokens, quote_type, isIndex):
            ...

    client = Client()
    # assign a handler for SIGALRM
    handler = signal(SIGALRM, _handler)
    try:
        # set the alarm
        alarm(TIMEOUT)
        return client.quotes(instrument_tokens=inst_tokens, quote_type="", isIndex=False)
    except Timeout:
        # alarm was triggered - i.e., client.quotes() took longer than TIMEOUT seconds
        pass
    finally:
        # make sure the alarm and its handler are reset
        alarm(0)
        signal(SIGALRM, handler)

for _ in range(MAXRETRIES):
    if (result := run_with_timeout('MSFT')) is not None:
        print(result)
        break
    print('Sleeping')
    sleep(SLEEP)
    print('Retrying')
else:
    print('Too many retries')