3

I'm looking for the most pythonic way of trying a command, catching if an error occurs and retrying by running a preparatory command and then the original command. Specifically in my case I'm looking to write a table to a database, catch if a "schema does not exist" error is thrown, then trying to create a schema and retrying the write table. Then, if the write table errors again I don't want to catch it.

So far I have (schematically):

try:
    write_to_table(table, schema)
except sqlalchemy.exc.ProgrammingError:
    create_schema(schema)
    write_to_table(table, schema)

This does what I want, but seems a bit off somehow, maybe because I'm duplicating write_to_table().

So what's the most pythonic way of doing the above?

P.S. When I say I'd like to retry, I do NOT want something like this: How to retry after exception?

  • That seems like the most straight forward way to do it… – deceze Nov 12 '19 at 09:28
  • Why don't you first call create_schema (if doesn't exists) and then call write_to_table within try block ? – S.N Nov 12 '19 at 09:32
  • You could use the retrying library which is handy enough. Or you could take the retry logic from there and do a custom implementation. https://pypi.org/project/retrying/ – JRajan Nov 12 '19 at 09:32
  • @Nair maybe a minor point, but most of the times the schema is there. So in your solution, most of the times you're sending an extra command to the DB which will fail. – pythonicpete Nov 12 '19 at 09:41
  • @pythonicpete, call create_schema (if doesn't exists) – S.N Nov 12 '19 at 11:41
  • @Nair how do I find out whether the schema exists or not? – pythonicpete Nov 12 '19 at 12:24

1 Answers1

0

Just create a reusable decorator !!

def retry(func):
        '''
        Decorator.
        If the decorated function fails with an exception 
        calls it again after a random interval.
        '''
        def _retry(*args,**kwargs):
            max_retries = 1
            for i in range(max_retries):
                try:
                    value = func(*args,**kwargs)
                    return value
                except sqlalchemy.exc.ProgrammingError as e:
                    print('function:[{}({},{})] Failed with error: {} . Retrying...'.format(func.__name__,str(*args),str(kwargs),str(e)))
                    time.sleep(random.uniform(1,3))
            print("Max_retries({}) exceeded for function {}".format(max_retries,func.__name__))
        return _retry

By using the above decorator, in which you can also configure the number of retriesand the retry interval, you can do the following:

@retry
write_to_table(table, schema)