Retries#

pjrpc supports request retries based on response code or received exception using customizable backoff strategy. pjrpc provides several built-in backoff algorithms (see pjrpc.client.retry), but you can implement your own one like this:

import dataclasses as dc
import random
from pjrpc.client.retry import Backoff

@dc.dataclass(frozen=True)
class RandomBackoff(Backoff):
    def __call__(self) -> Iterator[float]:
        return (random.random() for _ in range(self.attempts))

Retry strategy can be configured for all client requests by passing a strategy to a client constructor as a retry_strategy argument or for a particular request as a _retry_strategy when calling send method.

The following example illustrate request retries api usage:

import asyncio
import random

import pjrpc
from pjrpc.client.backend import aiohttp as pjrpc_client
from pjrpc.client.retry import ExponentialBackoff, PeriodicBackoff, RetryStrategy


async def main():
    default_retry_strategy = RetryStrategy(
        exceptions={TimeoutError},
        backoff=PeriodicBackoff(attempts=3, interval=1.0, jitter=lambda: random.gauss(mu=0.5, sigma=0.1)),
    )

    async with pjrpc_client.Client('http://localhost/api/v1', retry_strategy=default_retry_strategy) as client:
        response = await client.send(
            pjrpc.Request('sum', params=[1, 2], id=1),
            _retry_strategy=RetryStrategy(
                exceptions={TimeoutError},
                codes={2001},
                backoff=ExponentialBackoff(
                    attempts=3, base=1.0, factor=2.0, jitter=lambda: random.gauss(mu=0.5, sigma=0.1),
                ),
            ),
        )
        print(f"1 + 2 = {response.result}")

        result = await client.proxy.sum(1, 2)
        print(f"1 + 2 = {result}")


asyncio.run(main())