I'm developing a retry functionality automatically by a ErrorInterceptor
implementing HttpInterceptor
. I read that the retryWhen
is exactly what I need. What I want it to happen is conditionally retry on the clicking of the Snackbar 'RETRY' button and I don't want it to fire unlimited requests (so, maybe after 3 times you can't try again). The problem is that now is that I don't know how to conditionally retry after the action button is clicked on the notification snackbar
I already tried to just fire the notificationService which displays the notification with the simple code:
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(request).pipe(
retryWhen(error => {
this.notificationService.showNotification('problem RETRY', NotificationActionLabel.Retry, 4000, () => {
console.log('retrying');
return of(error);
});
return throwError(error);
}),
This doesn't retry the functionality anymore, it just stops.
I then found some code about retryWhen which describes a generalRetryStrategy https://www.learnrxjs.io/operators/error_handling/retrywhen.html. I added this but I want it to fire conditionally (linked to the action button).
I have a callback function on the Notification Service
export class NotificationService {
constructor(private snackBar: MatSnackBar) {}
public showNotification(message: string, action?: string, duration?: number, callBackFunction?: Function) {
const defaultDuration: number = 2500;
const notificationRef = this.snackBar.open(message, action, {
duration: duration == null ? defaultDuration : duration,
panelClass: ['snackbar-styling'],
});
notificationRef.onAction().subscribe(result => callBackFunction(result));
}
}
The interceptor is now as following:
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(request).pipe(
retryWhen(this.genericRetryStrategy()),
catchError((error: HttpErrorResponse) => {
let errorMessage = '';
// Client side error
if (error.error instanceof ErrorEvent) {
errorMessage = `Error: ${error.error.message}`;
} else {
// Server Side Error
errorMessage = this.generateErrorMessage(error);
}
this.loggingService.logErrorMessage(error.error.message);
this.notificationService.showNotification(errorMessage, null, 4000);
return throwError(error.error.message);
}),
);
with the following function genericRetryStrategy, notice this is hardly any different than the code from learn-rxjs.
genericRetryStrategy = ({
maxRetryAttempts = 3,
scalingDuration = 1000,
excludedStatusCodes = [],
}: {
maxRetryAttempts?: number;
scalingDuration?: number;
excludedStatusCodes?: HttpStatusCode[];
} = {}) => (attempts: Observable<any>) => {
return attempts.pipe(
mergeMap((error, i) => {
this.notificationService.showNotification('attempting', 'retry', 4000, () => {
const retryAttempt = i++;
// if maximum number of retries have been met
// or response is a status code we don't wish the retry, throw error
if (retryAttempt > maxRetryAttempts || excludedStatusCodes.find(e => e === error.status)) {
return throwError(error);
}
console.log(`Attempt ${retryAttempt}: retrying in ${retryAttempt * scalingDuration}ms`);
//retry after 1s, 2s, etc...
return timer(retryAttempt * scalingDuration);
});
return throwError(error);
}),
finalize(() => console.log('We are done!')),
);
};
I'm expecting it to only fire the retry functionality when the notification service callback function is really called (so the 'retry' button is clicked). Now it immediately skips the notification service call and just returns the error (throwError(error))
.
Any help is much appreciated.