connectrpc/connect-es

Client middleware that adds automatic retries to unary calls with timeouts between retry attempts.

BrRenat opened this issue · 3 comments

Is your feature request related to a problem? Please describe.
I'm frustrated with intermittent network issues causing failures in unary calls.

Describe the solution you'd like
Add automatic retry support with configurable timeouts to connect-es client middleware for unary calls.

Describe alternatives you've considered
Manual retry logic at the application level introduces complexity and duplication. Centralizing retries in the middleware ensures consistency and ease of maintenance.

Hey! Can you elaborate a bit more on unary calls failing, is it happening in the browser?

Yes, certain errors can be anticipated and retried, while others may not. The middleware should be configurable based on error codes. f.e network error or rate limit of api.

Including the middleware as part of the core package seems out of scope. The logic to when and how to retry is beyond the scope of an RPC library, it purely depends on the environment and the API being accessed. But implementing a unary retry is straightforward:

import {
  Code,
  ConnectError,
  type Interceptor,
} from "@connectrpc/connect";

const retryInterceptor: Interceptor = (next) => {
  return async (req) => {
    if (req.stream) {
      return await next(req);
    }
    for (let i = 0; ; i++) {
      try {
        return await next(req);
      } catch (err) {
        if (i == 5) {
          throw err;
        }
        const cErr = ConnectError.from(err);
        if (cErr.code == Code.ResourceExhausted) {
          // Wait for a bit and retry
          await new Promise((resolve) => setTimeout(resolve, 1000));
        } else {
          throw err;
        }
      }
    }
  };
};

As you can see most of the code is just to decide and when and how to retry. Closing this issue for now, feel free to reopen if needed.