"""Utility functions.""" from __future__ import annotations import json import random from datetime import timedelta from typing import Any from lambdacommon.common_config import logger from src.constants import RETRY_BASE_SECONDS, RETRY_EXPONENT, RETRY_JITTER_PCT def calc_retry_delta(retry_count: int) -> timedelta: """Calculate a time delta for the next retry. Uses exponential backoff with jitter to prevent thundering herd. Args: retry_count: The number of previous retry attempts. Returns: timedelta: Time to wait before next retry. """ # Calculate exponential backoff base_secs = RETRY_BASE_SECONDS * (RETRY_EXPONENT**retry_count) # Add jitter (plus/minus a percentage of base) jitter_secs = (2 * random.random() - 1) * (base_secs * RETRY_JITTER_PCT) # Return result delta_secs = base_secs + jitter_secs return timedelta(seconds=delta_secs) def try_json(value: Any) -> Any: """Attempt to parse a value as JSON. Args: value: The value to parse. If not a string, returns unchanged. Returns: Any: Parsed JSON if value is valid JSON string, otherwise original value. """ if not isinstance(value, str): return value try: return json.loads(value) except json.JSONDecodeError: logger.warning('Could not parse data as JSON') return value