Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

[Feat]: Add RetryTransport for automatic retry with exponential backoff

Open
#871 6 comments 0 reactions 1 assignee View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
45/100
Issue type
Feature
Clarity
Clearly specified
Activity status
Stale
Tech stack
grpc, python
Domain
api, backend

Research direction

Look at the existing transport classes (JsonRpcTransport, RestTransport, GrpcTransport) and the TenantTransportDecorator pattern. The new RetryTransport must wrap any ClientTransport. Start by examining the SDK's exception hierarchy (A2AClientError, A2AClientTimeoutError) and how they chain httpx and grpc errors. Write tests for the retry predicate and the on_retry hook. Ensure the implementation works for all three transports and does not retry domain errors.

Written by the indexing model from the issue text.

Description

component: client
Is your feature request related to a problem? Please describe.

The SDK's transports (JsonRpcTransport, RestTransport, GrpcTransport) raise immediately on transient failures (network errors, timeouts, rate limits, 5xx responses, gRPC UNAVAILABLE/RESOURCE_EXHAUSTED) with no built-in retry mechanism. Every caller has to reimplement the same retry/backoff loop, and to do it correctly they have to inspect __cause__ chains because A2AClientError doesn't expose HTTP status codes or gRPC codes directly.

Describe the solution you'd like

A RetryTransport decorator wrapping any ClientTransport, mirroring the existing TenantTransportDecorator pattern:

inner = JsonRpcTransport(httpx_client=client, agent_card=card)
transport = RetryTransport(base=inner, max_retries=3)

The default predicate retries on:

  • A2AClientTimeoutError (always).
  • A2AClientError chained from httpx.RequestError or httpx.HTTPStatusError(408/429/502/503/504).
  • A2AClientError chained from grpc.aio.AioRpcError(UNAVAILABLE/RESOURCE_EXHAUSTED).
  • Domain errors (TaskNotFoundError, etc.) are never retried.

retry_predicate is configurable for custom logic, and on_retry is exposed as a hook for logging/metrics. Streaming methods (send_message_streaming, subscribe) only retry before the first event is yielded.

Describe alternatives you've considered
  • Retry via ClientCallInterceptor — not feasible; after() only fires on successful results, so interceptors never see exceptions.
  • Transport-specific retry (httpx custom transport, gRPC retryPolicy / UnaryUnaryClientInterceptor) — operates below the SDK's exception layer, requires two separate configurations, and doesn't cover all three transports uniformly.
  • Retry inside each transport implementation — triples the logic across JsonRpcTransport, RestTransport, GrpcTransport and forces every future transport to reimplement it.
Additional context

Purely additive: new RetryTransport class, tests, and one export change. No new dependencies — the grpc import is conditional, matching the SDK's existing pattern. ClientFactory integration is left as a follow-up.

Code of Conduct
  • I agree to follow this project's Code of Conduct
Dominant language
Python
Stars
2.2k
Forks
496
Avg merge
2d 6h
Merged PRs (30d)
19

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from a2aproject/a2a-python

All issues in a2aproject/a2a-python

Similar issues

More Python issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.