Нулевой объект Flux.onErrorContinue () - PullRequest
0 голосов
/ 10 июля 2020

У меня проблема с onErrorContinue (), что объект, переданный Biconsumer, имеет значение null.

Я использую Spring boot 2.1.13.RELEASE и реактивный mon go с ядром реактора версии 3.2 .15.RELEASE.

Проблема возникает, когда вызов базы данных для получения записи с идентификатором не возвращает никакой записи, а с помощью оператора switchIfEmtpy () я генерирую исключение, используя Mono.error () и нижестоящий i попробуйте обработать это исключение с помощью onErrorContinue ().

Код ниже объясняет проблему:

public static void main(String[] args) {
    Flux.range(1, 10)
            .flatMap(integer -> mapInteger(integer))
            .doOnNext(System.out::println)
            .onErrorContinue((throwable, o) -> System.out.println("error with " + o)) // o is null
            .subscribe();
}

public static Mono<Integer> mapInteger(Integer num) { // This is here to simulate the db call
    return Mono.just(num)
            .flatMap(t -> {
                if (t == 5)
                    return Mono.empty();
                else
                    return Mono.just(num * 2);
            })
            .switchIfEmpty(Mono.error(new RuntimeException("Error happened while mapping integer!")));
}

Это напечатает следующие значения:

2
4
6
8
error with null
12
14
16
18
20

PS. У меня нет проблемы, когда в потоке возникает другая ошибка.

Обновление: mapInteger () должен был имитировать приведенный ниже вызов репозитория reactivemon go:

public Mono<MetaData> getFromDbByKey(String key) {
        return repository
            .findByKeyAndDeletedIsFalse(key)
            .switchIfEmpty(Mono.error(() -> new RuntimeException()));
    }

и вызов getFromDbByKey () возвращает эти метаданные, которые мне нужно сопоставить с потоком в основном потоке.

с onErrorContinue мы ловим Throwable и в зависимости от его типа выполняем различную обработку для каждого типа ошибки .

Ответы [ 2 ]

1 голос
/ 11 июля 2020

Вы не можете ожидать получить "элемент" t при возврате Mono.empty () if t == 5?

Этот код напечатает то, что вам нужно.

    Flux.range(1, 10)
        .flatMap(integer -> mapInteger(integer))
        .doOnNext(System.out::println)
        .onErrorContinue((throwable, o) -> {
          System.out.println(throwable.getMessage());
        })
        .subscribe();
  }
  public static Mono<Integer> mapInteger(Integer num) { // This is here to simulate the db call
    return Mono.just(num)
        .flatMap(t -> {
          if (t == 5)
            return Mono.empty();
          else
            return Mono.just(num * 2);
        })
        .switchIfEmpty(Mono.error(new RuntimeException("error with " + num)));
  }

выводит:

2
4
6
8
error with 5
12
14
16
18
20

И в вашем фактическом вызове mongoDB вы можете иметь что-то вроде:

public Mono<MetaData> getFromDbByKey(String key) {
        return repository
            .findByKeyAndDeletedIsFalse(key)
            .switchIfEmpty(Mono.error(() -> new RuntimeException("Couldnt find metadata which is not deleted for the key: " + key)));
    }
0 голосов
/ 13 июля 2020

Вот решение / обходной путь, который мне предложил коллега:

public static void main(String[] args) {

    Flux.range(1, 10)
        .flatMap(integer -> mapInteger(integer)
                           .switchIfEmpty(Mono.error(
                                new CustomException("Error happened while mapping integer!", 
                            integer))))
        .doOnNext(System.out::println)
        .onErrorContinue((throwable, o) -> {
            if (CustomException.class.isInstance(throwable))
                System.out.println("Object to blame " + ((CustomException)throwable).getBlamedObject());
            System.out.println("error with " + o);
        })
    .subscribe();
  }

  public static Mono<Integer> mapInteger(Integer num) {
      return Mono.just(num)
          .flatMap(t -> {
              if (t == 5)
                  return Mono.empty();
              else
                  return Mono.just(num * 2);
          });
  }

  public static class CustomException extends RuntimeException {
      private Integer blamedObject;

      public CustomException(String message, Integer blamedObject) {
          super(message);
          this.blamedObject = blamedObject;
      }

      public Integer getBlamedObject() {
          return blamedObject;
      }
  }

Это вернет:

2
4
6
8
Object to blame 5
error with null
12
14
16
18
20

Решение / обходной путь - создать настраиваемое исключение который принимает объект с ошибкой и перемещает switchIfEmpty () в основной поток, чтобы я мог получить объект, вызвавший проблему, а затем в onErrorContinue () я могу проверить тип исключения и получить объект, который вызвал проблему.

Это работает для меня, поскольку mapInteger () в этом примере - это просто симуляция реактивного репозитория mon go, который будет вернуть пустое моно, если в исходном сообщении не найдено результатов, обновленных.

...