0

my service is working with couchbase. when I want to update a document, first the service performs a lookup and gets the document with CAS, and then it updates the document. if the update failed with CASMismatch exception I want to perform retry with delay (retry when) on the lookUp (async request) and update. the problem is that retry invokes only the update observable and not the entire lookUp and update async requests.

this is retry code:

`    public Func1<Observable<? extends Throwable>, Observable<?>> getRetryOnCASMismatchExceptionHandler(String unrecoverableErrorMessage) {
        return observable -> observable
                .zipWith(Observable.range(1, maxAttempts), ImmutablePair::of)
                .flatMap(pair -> {
                    var throwable = pair.left;
                    var attemptsCounter = pair.right;
                    if (throwable instanceof CASMismatchException) {
                        // Retry code
                        return Observable.timer((long) attemptsCounter * backoffMs, TimeUnit.MILLISECONDS);
                    }
                    // Pass the throwable
                    return Observable.error(new RuntimeException(unrecoverableErrorMessage, throwable));
                });
    }`

the update code:

     private Observable<String> updateDetectionWithRetry(DetectionFeed detectionFeed, String userId, String detectionPath) 
     {
            updateDetection(detectionFeed, userId, detectionPath)
            .retryWhen(retryHandlers.getRetryOnCASMismatchExceptionHandler("Failed to update persisted UserAccount with detection data [" + detectionFeed.toString() + "]"));
     }
    
     private Observable<String> updateDetection(DetectionFeed detectionFeed, String userId, String detectionPath) 
     {
         return userRepo
             .lookupDetection(userId, detectionPath)
             .filter(existingDetection -> isNewDetectionFeed(existingDetection, detectionFeed))
             .flatMap(detectionToPersist -> userRepo.replaceDetection(userId, detectionPath,
                      createDetectionToPersist(detectionFeed), detectionToPersist.getCas()))
     }
Etay Ceder
  • 160
  • 1
  • 9

1 Answers1

0
Observable.defer(() -> updateDetection(detectionFeed, userId, detectionPath))

Observable.defer() will wrap the method in observable, every error will retry the all process (lookUp and replace)

this is the full proper code:

private Single<Optional<String>> updateUserAccountDetection(DetectionFeed detectionFeed, String userId, String detectionPath) {
    return Observable.defer(() -> updateDetection(detectionFeed, userId, detectionPath))
            .retryWhen(RetryBuilder
                    .anyOf(CASMismatchException.class)
                    .delay(Delay.fixed(1L, TimeUnit.SECONDS))
                    .max(3)
                    .build())
            .map(Optional::ofNullable)
            .toSingle();
}
Etay Ceder
  • 160
  • 1
  • 9