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

1#!/usr/bin/python 

2 

3# SPDX-FileCopyrightText: 2023-2025 Arcangelo Massari <arcangelo.massari@unibo.it> 

4# 

5# SPDX-License-Identifier: ISC 

6 

7from __future__ import annotations 

8 

9import random 

10import time 

11from functools import wraps 

12from typing import Any, Callable, Optional, TypeVar, Union 

13 

14T = TypeVar('T') 

15 

16 

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. 

22  

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 

32 

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) 

41 

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) 

48 

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)