feat: Controlling retry behavior of `useSubscription`
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 40.6k
- Forks
- 1.7k
- Avg merge
- 1d 22h
- Merged PRs (30d)
- 22
Description
Describe the feature you'd like to request
Allow controlling retry behavior for httpSubscriptionLink on a per-request basis via the useSubscription hook options. Currently, httpSubscriptionLink automatically retries on certain error codes (INTERNAL_SERVER_ERROR, BAD_GATEWAY, SERVICE_UNAVAILABLE, GATEWAY_TIMEOUT) without any way to opt out. This retry logic seems to be hardcoded in the link and happens before onError is called, making it impossible to prevent from the call site. For subscriptions that trigger side effects (e.g., sending a message to an AI conversation), automatic retries can cause duplicate operations on the backend.
Describe the solution you'd like to see
Maybe add a retry option directly to useSubscription:
api.conversation.streamMessages.useSubscription(
{ conversationId },
{
onData: (data) => { /* ... */ },
onError: (error) => { /* ... */ },
retry: false // or a function: (error) => boolean
}
);
Describe alternate solutions
I tried a few things without finding success.
- Using the
retryLinkand checking for an error code. I updated my backend (what the subscription ends up calling) to simply respond with a 500 for testing and theretryLinkwasn't even hit. So I don't think I can control it? The event source data contains:
event: connected
data: {}
event: serialized-error
data: { /* a big ol json blob */ }
Here is what my retryLink:
splitLink({
condition: (op) => op.type === 'subscription',
true: [
retryLink({
retry: (opts) => {
console.log('retrying'); // This is not logged
opts.op.type;
const code = opts.error.data?.code;
if (!code) {
console.error('No error code found, retrying');
return true;
}
if (code === 'INTERNAL_SERVER_ERROR') {
return false;
}
return false;
}
}),
httpSubscriptionLink({
url: `${getBaseUrl()}/api/trpc`,
transformer: superjson
})
],
false: httpBatchLink({
url: `${getBaseUrl()}/api/trpc`,
transformer: superjson
})
})
- I also attempted to use a
useEffectin the component where myuseSubscriptionis established. I'm able to prevent retries here, but I don't seem to be able to discern the error code to check for only INTERNAL_SERVER_ERROR. This might be user error on my part, but inspected everything about the error and didn't see access to a code.
useEffect(() => {
if (subscription.status === 'connecting' && subscription.error) {
subscription.reset();
resetStreamingState(subscription.error.message || 'An error occurred while processing your message.');
}
}, [subscription, resetStreamingState]);
Additional information
My use case here is:
- React page uses a subscription to send a message to a chat bot backend type thing. Works great
- If an error occurs during the request (you close your laptop or the server responds with a 500), the subscription retries automatically and the message is sent to the chat again
- I want to prevent retrying in certain cases
As far as I can tell, the event source event: serialized-error prevents me from using the existing tooling tRPC provides for controlling this.
Thanks so much for your time and attention! Huge fan of the library and appreciate all you do :)
👨👧👦 Contributing
- 🙋♂️ Yes, I'd be down to file a PR implementing this feature!
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start at the useSubscription options and trace how httpSubscriptionLink handles the listed retryable errors, including the serialized-error event and the point before onError. Compare that path with retryLink. Done means a per-request false or predicate option can control retries without breaking existing behavior, with coverage for the requested error cases.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- react, typescript
- Domain
- api
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100