Skip to content
ub3r.io

SDK Design · Chapter 3 · 10 min

Retries and timeouts in SDKs

Default retry policy, idempotency integration and per-call overrides.

Intelligent retry strategies

Network reliability is never guaranteed, so a robust SDK must handle transient failures automatically. The ub3r client implements exponential backoff with jitter to prevent overwhelming the platform during a recovery phase. We automatically retry connection timeouts and server-side errors that are likely to be temporary. By limiting the number of retries to a sane default, we prevent requests from hanging indefinitely and consuming resources.

Not all errors should be retried, as some indicate permanent failures that require developer intervention. For example, a 400 Bad Request or a 401 Unauthorized should never be retried because the result will always be the same. The SDK intelligently filters these status codes to ensure that we only retry when there is a genuine chance of success. This targeted approach improves performance and reduces unnecessary traffic on the network.

Automated idempotency

When retrying a POST request, there is a risk of creating duplicate resources if the previous attempt actually succeeded on the server. The ub3r SDK mitigates this by automatically generating and attaching idempotency keys to every retry attempt. This ensures that even if a network hiccup prevents you from receiving a success response, the server will not process the same message twice. Idempotency is a critical feature for financial and communication platforms where duplicates can be costly.

Developers can also provide their own idempotency keys if they want to ensure safety across application restarts. This is particularly useful for background workers that might be killed and restarted by an orchestrator. By integrating idempotency deeply into the SDK's core, we make the "safe" way of working the default way. This abstraction allows developers to focus on their business logic rather than low-level distributed systems challenges.

ts
// The SDK handles the idempotency key automatically behind the scenes
await client.messages.create({
  to: "+15550100",
  text: "Safe retry message"
}, { maxRetries: 3 });

Timeout management

Global timeouts are essential for preventing slow requests from clogging up your application's connection pool. The ub3r SDK sets a default timeout of 30 seconds for all operations, which is sufficient for most global networks. However, for latency-sensitive operations like sending an OTP, you might want to override this to a much lower value. Our per-call configuration allows you to tune these parameters without having to instantiate a new client.

Properly handling timeouts also requires cleaning up resources such as sockets and timers to prevent memory leaks. The ub3r library uses modern abort controllers to signal cancellations to the underlying HTTP stack efficiently. This ensures that once a timeout is reached, the connection is severed and resources are returned to the system immediately. Managing these details correctly is what separates a production-grade SDK from a simple wrapper.

Discussion (4)

TH
Tomás Herrera · 2026-10-07

We learnt the idempotency lesson the expensive way: duplicate OTPs during an incident. This chapter is now required reading on my team.

LF
Lena Fischer · 2026-10-12

Same experience here. Per-route metrics were the only way we found it.

AT
Aiko Tanaka · 2026-10-08

Clear and opinionated. One nit: worth mentioning clock skew between producer and consumer when choosing the tolerance window.

SO
Samuel Okafor · 2026-10-09

The callout about alerting on queue age instead of depth changed how we page people. Thank you.