web-dev-qa-db-fra.com

Comment gérer les erreurs lors de l'exécution de Flux.map ()

J'essaie de comprendre comment gérer les erreurs lors du mappage d'éléments dans un flux.

Par exemple, j’analyse une chaîne CSV dans l’un de mes POJOs:

myflux.map(stock -> converter.convertHistoricalCSVToStockQuotation(stock));

Certaines de ces lignes peuvent contenir des erreurs. Ce que je trouve dans le journal est:

 reactor.core.publisher.FluxLog:  onNext([SOME_BOGUS_QUOTE]@38.09 (Fri Apr 08 00:00:00 CEST 2016) H(38.419998)/L(37.849998)/O(37.970001))
 reactor.core.publisher.FluxLog:  onNext([SOME_BOGUS_QUOTE]@38.130001 (Thu Apr 07 00:00:00 CEST 2016) H(38.189999)/L(37.610001)/O(37.799999))
 reactor.core.publisher.FluxLog:  onError(Java.lang.IllegalArgumentException: Invalid CSV stock quotation: SOME_BOGUS_QUOTE,trololo)
 reactor.core.publisher.FluxLog:  Java.lang.IllegalArgumentException: Invalid CSV stock quotation: SOME_BOGUS_QUOTE,trololo

J'ai lu dans l'API des méthodes de traitement des erreurs, mais la plupart ont renvoyé le renvoi d'une "valeur d'erreur" ou l'utilisation d'un flux de repli, comme celui-ci:

Flux.onErrorResumeWith(myflux, x -> Mono.fromCallable(() -> ... do stuff);

Cependant, utiliser ceci avec ma myflux signifie que tout le flux est traité à nouveau.

Alors, y a-t-il un moyen de gérer les erreurs lors du traitement d'éléments particuliers (c'est-à-dire de les ignorer/de les consigner) et de continuer à traiter le reste du flux?

MISE À JOUR AVEC la solution de contournement @akarnokd

public Flux<StockQuotation> getQuotes(List<String> tickers)
{
    Flux<StockQuotation> processingFlux = Flux.fromIterable(tickers)
    // Get each set of quotes in a separate thread
    .flatMap(s -> Mono.fromCallable(() -> feeder.getCSVQuotes(s)))
    // Convert each list of raw quotes string in a new Flux<String>
    .flatMap(list -> Flux.fromIterable(list))
    // Convert the string to POJOs
    .flatMap(x -> {
            try {
                return Flux.just(converter.convertHistoricalCSVToStockQuotation(x));    
            }
            catch (IllegalArgumentException ex){
                System.out.println("Error decoding stock quotation: " + x);
                return Flux.empty();
            }
    });

    return processingFlux;
}

Cela fonctionne comme un charme, cependant, comme vous pouvez le constater, le code est moins élégant qu'avant. L'API Flux n'a-t-il aucune méthode pour faire ce que ce code fait?

retry(...)
retryWhen(...)
onErrorResumeWith(...)
onErrorReturn(...)
14
Victor

Au lieu de cela, vous avez besoin de flatMap qui vous permet de retourner une séquence vide si le traitement échoue:

myflux.flatMap(v -> {
    try {
        return Flux.just(converter.convertHistoricalCSVToStockQuotation(stock));
    } catch (IllegalArgumentException ex) {
        return Flux.empty();
    }
});
13
akarnokd

Si vous souhaitez utiliser les méthodes de Reactor 3 pour traiter les exceptions, vous pouvez utiliser Mono.fromCallable.

flatMap(x -> 
    Mono.fromCallable(() -> converter.convertHistoricalCSVToStockQuotation(x))
        .flux()
        .flatMap(Flux::fromIterable)
        .onErrorResume(Flux::empty)
)

Malheureusement, il n'y a pas de Flux.fromCallable, donc si l'appelable renvoie une liste, vous devez la convertir manuellement en Flux.

11

Avec la version actuelle de Reactor 3, de nombreuses méthodes ont été ajoutées. Pour que nous puissions faire quelque chose comme ceci:

Flux.onErrorResume(error -> { 
        System.out.println("Error decoding stock quotation: " + e);
        return Flux.empty();
    });

Voir plus d'informations sur la façon de gérer les erreurs ici

3
code4kix

Vous pouvez utiliser onErrorContinue. Il permet de remédier aux erreurs en supprimant l’élément problématique et en poursuivant les éléments suivants.

0
seanzxx