Coverage for rdflib_ocdm / retry_utils.py: 94%
24 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-03-21 12:35 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-03-21 12:35 +0000
1#!/usr/bin/python
3# SPDX-FileCopyrightText: 2023-2025 Arcangelo Massari <arcangelo.massari@unibo.it>
4#
5# SPDX-License-Identifier: ISC
7from __future__ import annotations
9import random
10import time
11from functools import wraps
12from typing import Any, Callable, Optional, TypeVar, Union
14T = TypeVar('T')
17def execute_with_retry(func: Callable[..., T], *args: Any, max_retries: int = 5,
18 base_wait_time: int = 1, reporter: Any = None, **kwargs: Any) -> T:
19 """
20 A function that executes the given function with retry logic and exponential backoff.
21 This is useful when you can't use the decorator directly.
23 :param func: The function to execute with retry logic
24 :param args: Positional arguments to pass to the function
25 :param max_retries: Maximum number of retry attempts before giving up
26 :param base_wait_time: Initial wait time in seconds, which will be increased exponentially
27 :param reporter: Optional reporter object with add_sentence method for logging
28 :param kwargs: Keyword arguments to pass to the function
29 :return: The result of the function call
30 """
31 retry_count = 0
33 while retry_count <= max_retries: 33 ↛ exitline 33 didn't return from function 'execute_with_retry' because the condition on line 33 was always true
34 try:
35 return func(*args, **kwargs)
36 except Exception as e:
37 retry_count += 1
38 if retry_count <= max_retries:
39 # Calculate wait time with exponential backoff and some randomness
40 wait_time = (base_wait_time * (2 ** (retry_count - 1))) + (random.random() * 0.5)
42 # Log the retry attempt
43 message = f"Query attempt {retry_count}/{max_retries} failed: {e}. Retrying in {wait_time:.2f} seconds..."
44 if reporter and hasattr(reporter, 'add_sentence'):
45 reporter.add_sentence(message)
46 else:
47 print(message)
49 time.sleep(wait_time)
50 else:
51 # All retries failed
52 error_message = f"Failed after {max_retries} attempts: {e}"
53 if reporter and hasattr(reporter, 'add_sentence'): 53 ↛ 55line 53 didn't jump to line 55 because the condition on line 53 was always true
54 reporter.add_sentence(f"[ERROR] {error_message}")
55 raise ValueError(error_message)