Reputation: 11
Question is based off Reactive Patterns with RxJS for Angular by Lamis Chebbi. Chapter 5: Error Handling. In the section covering 'retrying strategies'. My problem stems from an example used in the book featuring the soon to be deprecated retryWhen operator.
Here's the relevant observable logic, provided through a dedicated service observable.service.ts
export class ObservableService {
observable$ = from(['1', '2', '3', 'Hello', '100']);
}
Here is the relevant code in the consuming component app.component.ts
ngOnInit() {
this.observableService.observable$.pipe(
map((value) => { if (isNaN(value as any)) { throw new Error } else return parseInt(value); }),
retryWhen((errors) => { return errors.pipe(delayWhen(() => timer(5000))); }),
).subscribe({
next: (value) => console.log('Value emitted', value),
error: (error) => console.log('Error: ', error),
complete: () => console.log('Stream completed'),
});
}
}
And the output which repeats every 5 seconds indefinitely
Value emitted 1
Value emitted 2
Value emitted 3
From my understanding, it loops because retryWhen
catches map()
's errors and uses them as its notifier's event stream; which upon emitting resubscribes retryWhen
to the source observable. map()
will always throw in this example.
This is fine. The problem is attempting to use retry
similarly. RxJS recommends using this operator over retryWhen
moving forward, and in doing so I run into issues. Namely, I'm not sure if retry
catches errors the same way.
Here is my attempt at producing the same output using retry
in place of retryWhen
in the consuming component app.component.ts
ngOnInit() {
this.observableService.observable$.pipe(
map((value) => { if (isNaN(value as any)) { throw new Error } else return parseInt(value); }),
retry({ delay: (error) => { return error.pipe(delayWhen(() => timer(5000))); } }),
).subscribe({
next: (value) => console.log('Value emitted', value),
error: (error) => console.log('Coming from observer error handling function: ', error),
complete: () => console.log('Stream completed'),
});
}
Which produces
Value emitted 1
Value emitted 2
Value emitted 3
Coming from observer error handling function: TypeError: error.pipe is not a function
at delay (app.component.ts:22:48)
at retry.js:42:99
at OperatorSubscriber._error (OperatorSubscriber.js:23:21)
at OperatorSubscriber.error (Subscriber.js:40:18)
at OperatorSubscriber._next (OperatorSubscriber.js:16:33)
at OperatorSubscriber.next (Subscriber.js:31:18)
at Observable._subscribe (innerFrom.js:51:24)
at Observable._trySubscribe (Observable.js:37:25)
at Observable.js:31:30
at errorContext (errorContext.js:19:9)
My goal is to reproduce the output shown in the book. Insight on getting the retry
logic's output to loop indefinitely would be appreciated. Background on what's going on behind the scenes would be a nice-to-have. My leading assumption is retry
's not receiving map()
's errors. Thanks
Upvotes: 1
Views: 799
Reputation: 8062
Use
retry({ delay: 5000 }),
Here's the doc on the RetryConfig
retryWhen is passed a lambda whose parameter is observable stream of errors. This reifies errors as observable events, which is pretty much never useful and became a source of confusion unto itself. Pretty much no other operator works this way, though it's not too hard to get this behavior back.
You can use RetryConfig's delay property to either set a delay in ms directly or you can return an observable time like before.
retry({ delay: _ => timer(5000) }),
Upvotes: 0