0

I'm using a PublishSubject in retryWhen to allow the user to retry the operation similarly to this answer. everything works fine but there's one problem - after 3 times the user clicked retry I should not allow the retry anymore and should abort the operation. is there a way to limit the retry to 3 times? I've tried publishSubject.take(3) operator but it didn't worked.

Ofek Regev
  • 467
  • 4
  • 18
  • Please provide the `retryWhen` setup you were using. As I mentioned before, you can't stop a `flatMap` from inside by giving it an empty source. – akarnokd Feb 25 '19 at 10:32
  • I still don't have a retryWhen setup that works as I want it to work, if I would then no question would have been asked, I'm still trying to find a setup that works with my requirements... – Ofek Regev Feb 25 '19 at 10:36
  • "I'm using a PublishSubject in retryWhen". So do you have code or don't? – akarnokd Feb 25 '19 at 10:40
  • As I mentioned I have a test setup which is the same as this [answer](https://stackoverflow.com/questions/47672224/retry-a-call-with-retrofit-2-and-rxjava2-after-displaying-a-dialog/47677308#47677308) but it doesn't fully fit with my requirements. – Ofek Regev Feb 25 '19 at 10:42
  • So what's stopping you to apply `take(3)` on the sequence returned from within `retryWhen`? – akarnokd Feb 25 '19 at 11:35

2 Answers2

1

Operators, such as retryWhen have a secondary flow whose outcome affects the primary flow. Consequently, flow manipulation can be performed on this secondary flow as well, thus you can apply all sorts of operators to shape its outcome:

Adapting this: https://stackoverflow.com/a/47677308/61158

final PublishSubject<Object> retrySubject = PublishSubject.create();

disposable.add(
    getData()
    .doOnError(throwable -> enableButton())
    .retryWhen(observable -> 
        observable.zipWith(retrySubject, 
             (o, o2) -> o
        )
        .take(3)  // <------------------------ maximum 3 items from the secondary sequence
        .concatWith(Observable.error(new RetriesExhaustedException()));
     )
    .subscribeWith(/* do what you want with the result*/)
);
akarnokd
  • 69,132
  • 14
  • 157
  • 192
  • One last question, in this case changing from PublishSubject to SingleSubject will affect the take(3) operation? I would like to reduce pitfalls and allow emitting only onNext() or onError() – Ofek Regev Feb 26 '19 at 09:54
  • Please think about what `SingleSubject` represents. – akarnokd Feb 26 '19 at 11:13
  • it means it will only emit 1 value or error, so I thought I will just create a new one in the flat map of the errorObservable. but it's hard to test whether it will defect the take(3) operation or not. – Ofek Regev Feb 26 '19 at 11:47
  • That makes no sense. What will call `onSuccess`/`onError` on those distinct `SingleSubject`s? – akarnokd Feb 26 '19 at 11:53
  • I'm passing it to the error handler by an interface method - void onConnectionFailed(SingleSubject retrySubject);. And the error handler can choose to either call retrySubject.onError() and abort the retry or call retrySubject.onSuccess() to retry – Ofek Regev Feb 26 '19 at 11:57
  • and to onConnectionFailed(retrySubject) I'm calling from retrySubject.doOnSubscribe() – Ofek Regev Feb 26 '19 at 13:39
0

Instead of using retry or retryWhen, why not try this solution based on errors catch operation

let count = 0;
let retry_limit = 2;
from([1])
  .pipe(
    catchError((err, obs) => {
       if (count >= retry_limit) {
         return throwError(err)
       }
       count++
       return obs.pipe(delay(500))
  })
);
Serhii
  • 51
  • 2
  • 7