a2aproject / a2aproject/a2a-python

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

Đang mở
#871 6 bình luận 0 reaction 1 người được giao Được giao cho @cchinchilla-dev Xem trên GitHub
component: client
Ngôn ngữ chính
Python
Star
2.1k
Fork
496
Merge trung bình
4 ngày 17 giờ
Pull request đã merge (30 ngày)
12

Mô tả

### 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:

```python
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

- [x] I agree to follow this project's Code of Conduct

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Đánh giá

Issue này chưa được đánh giá.

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.