Run a database transaction with dbpool.runInteraction, but retry the
        transaction in case of a temporary error (like connection lost).

        This is needed to be robust against things like database connection
        idle timeouts.

        The passed callable that implements the transaction must be retryable,
        ie. it must not have any destructive side effects in the case where
        an exception is thrown and/or rollback occurs that would prevent it
        from functioning correctly when called again.

def runInteractionWithRetry(self, actionFn, *args, **kw):
        """
        Run a database transaction with dbpool.runInteraction, but retry the
        transaction in case of a temporary error (like connection lost).

        This is needed to be robust against things like database connection
        idle timeouts.

        The passed callable that implements the transaction must be retryable,
        ie. it must not have any destructive side effects in the case where
        an exception is thrown and/or rollback occurs that would prevent it
        from functioning correctly when called again."""

        def runWithRetry(txn, *args, **kw):
            retryCount = 0
            while(True):
                try:
                    return actionFn(txn, *args, **kw)
                except txn.OperationalError:
                    retryCount += 1
                    if retryCount >= 5:
                        raise
                    excType, excValue, excTraceback = sys.exc_info()
                    log.msg("Database transaction failed (caught exception %s(%s)), retrying ..." % (
                        excType, excValue))
                    txn.close()
                    txn.reconnect()
                    txn.reopen()

        return self.dbpool.runInteraction(runWithRetry, *args, **kw)