I'm have implemented node grpc client retry using interceptor but it is only retrying once and not upto maxRetries which is specified. Also, the error is not propagating to the caller. Can you please where i'm missing in fixing this?
function createRetryInterceptor(maxRetries = 3, backoffInterval) {
return function (options, nextCall) {
let retries = 0;
return new grpc.InterceptingCall(nextCall(options), {
start: function (metadata, listener, next) {
function retryOrNext(status) {
if (status.code === grpc.status.UNAVAILABLE && retries < maxRetries) {
retries++;
console.log(`Retry ${retries} after ${backoffInterval}ms`);
console.error('Error message:', status.details);
// Create a new call with the same options
const call = nextCall(options);
call.start(metadata, listener, retryOrNext);
// Add a timeout for retry
setTimeout(() => {
call.cancel(); // Cancel the retry call if it takes too long
}, backoffInterval);
} else {
// Propagate errors from interceptor as well
if (status.code !== grpc.status.OK) {
next(status);
//return; // Exit the retry loop if not OK or UNAVAILABLE
}
// Proceed with successful call or other non-retriable errors
next(status);
}
}
// Wrap the listener to handle potential errors in onReceiveStatus
const wrappedListener = {
onReceiveStatus: function (status, next) {
try {
retryOrNext(status);
} catch (error) {
console.error('Error in onReceiveStatus:', error);
next(status);
}
},
// Forward other listener methods if present
...listener,
};
next(metadata, wrappedListener);
}
});
};
}
static promiseBuilderFn(resolve, reject) {
return (err, response) => {
if (err != null) {
console.log(`error in calling promise err: ${err}`);
reject(err);
} else {
console.log(`success: ${response}`);
resolve(response);
}
};
}
The grpc client i have created is like below
const client = new MyClient(
'localhost:5001',
grpc.credentials.createInsecure(),
{interceptors: [createRetryInterceptor(3, 5000)]}
);
and i'm calling the grpc service method as follows
return new Promise((resolve, reject) => {
client.getData(
request,
metadata,
promiseBuilderFn(resolve, reject)
);
})
I tried implementing the interceptor as mentioned in https://github.com/grpc/proposal/blob/master/L5-node-client-interceptors.md#examples but it is giving error as TypeError: nextCall is not a function