2015-01-20 16 views
7

Sono nuovo a ReactiveX e alla programmazione reattiva in generale. Devo implementare un meccanismo di riprova per le operazioni CAS Couchbase, ma l'esempio sul sito web Couchbase mostra un nuovo tentativo, che sembra riprovare indefinitamente. Devo avere un limite di tentativi e ritentare il conteggio da qualche parte.RxJava: retryWhen with retry limit

Il semplice retry() funzionerebbe, poiché accetta un retryLimit, ma non voglio che torni su ogni eccezione, solo su CASMismatchException.

Qualche idea? Sto usando la libreria RxJava.

risposta

2

retryWhen è chiaramente un po 'più complicato di semplice tentativi, ma qui è l'essenza di esso:

  • si passa una funzione notificationHandler a retryWhen che prende un Observable<Throwable> ed emette un Observable<?>
  • l'emissione di questo restituito Osservabile determina quando il tentativo dovrebbe verificarsi o si ferma
  • così, per ciascuna Eccezione che si verifica nel flusso originale, se quella del gestore emette 1 elemento, ci sarà 1 nuovo tentativo. Se emette 2 articoli, ci sarà 2 ...
  • non appena il flusso del gestore emette un errore, il tentativo viene interrotto.

Con questo, è possibile sia:

  • lavoro solo su CasMismatchExceptions: basta avere la funzione restituisce un Observable.error(t) in altri casi solo
  • tentativi per un determinato numero di volte: per ogni eccezione, flatMap da un numero Observable.range che rappresenta il numero massimo di tentativi, restituire un numero Observable.timer utilizzando il numero di tentativi # se è necessario aumentare i ritardi.

vostro caso d'uso è abbastanza vicino a quello in RxJava doc here

+0

Voglio utilizzare il tentativo quando si dispone di una limitazione del conteggio. Ho provato Observable.range (0, 10) ma non funziona. –

8

In aggiunta a quanto detto Simon Basilea, qui è una versione veloce con backoff lineare:

.retryWhen(notification -> 
    notification 
    .zipWith(Observable.range(1, 5), Tuple::create) 
    .flatMap(att -> 
      att.value2() == 3 ? Observable.error(att.value1()) : Observable.timer(att.value2(), TimeUnit.SECONDS) 
    ) 
) 

nota che " att "ecco una tupla che consiste sia del throwable sia del numero di tentativi, in modo da poter implementare in modo molto specifico una logica di ritorno basata su quei due parametri.

Se volete saperne ancora di più, si può sbirciare il doc resiliente Attualmente sto scrivendo: https://gist.github.com/daschl/db9fcc9d2b932115b679#retry-with-delay

+0

Qualcuno può spiegare, perché flatMap è richiesto qui? Sembra che il ritardo non funzioni senza di esso – deviant

2

far rivivere questa discussione in quanto nella Couchbase Java SDK 2.1.2 c'è un nuovo modo più semplice per farlo : utilizzare RetryBuilder:

Observable<Something> retryingObservable = 
sourceObservable.retryWhen(
    RetryBuilder 
    //will limit to the relevant exception 
    .anyOf(CASMismatchException.class) 
    //will retry only 5 times 
    .max(5) 
    //delay doubling each time, from 100ms to 2s 
    .delay(Delay.linear(TimeUnit.MILLISECONDS, 2000, 100, 2.0)) 
    .build() 
); 
+0

Puoi aggiungere diverse eccezioni con ritardi diversi? E puoi anche impostare un ritardo predefinito su tutto il resto? –

+0

No, dovrai semplicemente concatenare più tentativiWhen, ognuno con il suo builder, come se avessi messo in catena diversi blocchi catch nel codice imperativo –