Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Refactor: Extract duplicate retry logic into shared strategy class #1

@karlwaldman

Description

@karlwaldman

Description

The retry logic is duplicated between the sync client (client.py) and async client (async_client.py), with over 170 lines of nearly identical code. This violates the DRY (Don't Repeat Yourself) principle and makes maintenance harder.

Current State

Both OilPriceAPI (sync) and AsyncOilPriceAPI have nearly identical retry logic with exponential backoff, error handling, and rate limit detection. The only differences are:

  • time.sleep() vs await asyncio.sleep()
  • response.json() vs await response.json()

Proposed Solution

Extract retry logic into a shared strategy class:

class RetryStrategy:
    """Abstract retry logic for both sync and async clients."""

    def __init__(self, max_retries: int = 3, retry_on: List[int] = None):
        self.max_retries = max_retries
        self.retry_on = retry_on or [429, 500, 502, 503, 504]

    def should_retry(self, attempt: int, status_code: int) -> bool:
        return (
            status_code in self.retry_on
            and attempt < self.max_retries - 1
        )

    def wait_time(self, attempt: int) -> float:
        return min(2 ** attempt, 60)

Benefits

  1. Single Source of Truth: One place to update retry logic
  2. Easier Testing: Test retry strategy independently
  3. Consistency: Guaranteed identical behavior between sync/async
  4. Maintainability: Changes only need to be made once

Impact

  • Breaking Changes: None (internal refactoring only)
  • Lines Saved: ~150 lines of duplicated code
  • Risk: Low - well-tested functionality

Acceptance Criteria

  • Create RetryStrategy class in new file oilpriceapi/retry.py
  • Update OilPriceAPI to use strategy
  • Update AsyncOilPriceAPI to use strategy
  • All existing tests pass without modification
  • Add unit tests for RetryStrategy class

Priority

Low - Quality-of-life improvement for v1.1 or v2.0. Current implementation works correctly.

References

Related files:

  • oilpriceapi/client.py (lines 163-250)
  • oilpriceapi/async_client.py (lines 120-193)

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestrefactoringCode improvement without changing functionalitytechnical-debtTechnical debt that should be addressed

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions