Рубрики
Без рубрики

Простое отслеживание времени в RxJava и Reactor

Существует множество способов отслеживания проблем с производительностью и неожиданно трудоемких методов, начиная с q… Помеченный как java, трассировка, rxjava, реактивный.

Существует множество способов отслеживания проблем с производительностью и неожиданно трудоемких методов, от быстрого и простого измерения времени от начала до конца метода до более полного (и сложного) CPU flamegraph или даже классики, такой как дамп потока, профилирование процессора и т. Д.

Во многих случаях для отладки достаточно просто поработать с метками времени и сравнить их. Но с асинхронной парадигмой это может быть слишком наивным способом.

Например, в контексте RxJava такого рода утверждения в методе:

Instant start = Instant.now();
Flowable promise = itemRepository.findAllById(idList);
log.info("{}", Duration.between(start, Instant.now());
return promise;

на самом деле не будет регистрироваться время, затраченное на извлечение хранилища.

Сделать старое снова новым

К счастью, RxJava поставляется с удобным оператором для измерения того, сколько времени и наблюдений прошло с момента подписки до ее завершения: timeInterval() (У реактора есть аналогичный оператор, о котором я расскажу позже)

временной интервал() doc объясняет, что он будет измерять длительность в миллисекундах и заключать ранее выданное значение в объект, содержащий как значение, так и измеренную задержку. В предыдущем примере Текучий<Элемент> стал бы Текучий<Приуроченный<Элемент>> .

Таким образом, мы можем написать наш код следующим образом:

return itemRepository.findAllById(idList)
                .timeInterval()
                .map(timed -> {
                    log.info("{}", timed.time());
                    timed.value();
                });

На этот раз мы эффективно регистрируем продолжительность получения товаров.

Но все еще есть тонкость: выполнение этого на потоке может привести к фатальному получению журнала для каждого элемента, обратите внимание на общее. Что делать, если я выполняю вызовы API для множества элементов? Вот и все:

Flowable.fromIterable(idList)
            .map(apiClient::getItemInfo)
            .timeInterval()
            .map(timed -> {
                log.info("{}", timed.time());
                return timed.value();
            });

Мы получим журнал для каждого идентификатора, так как у нас много вызовов API и столько же подписок на .map(ApiClient::getItemInfo) .

Вы тоже говорили о Реакторе

Реактор предоставляет свой собственный оператор, называемый истекший() . Это очень похоже на его возврат a Поток<Кортеж2 <<< , кортеж2, имеющий методы gett1() (получить левое значение, здесь длительность в миллисекундах) и getT2() (получить правильное значение, значение, выданное предыдущим вызовом).

Таким образом, приведенный выше код будет выглядеть следующим образом:

Flux.fromIterable(idList)
            .map(apiClient::getItemInfo)
            .elapsed()
            .map(tuple -> {
                log.info("{}", tuple.getT1());
                return tuple.getT2();
            });

Теперь представьте, что вы где-то разместили статическую длинную сводную статистику и готовы быстро экспортировать минимальные/максимальные, средние и подсчеты относительно сложного набора операций, таких как, например, вызов двух API, объединение их результатов и помещение некоторой информации в кэш Redis.

Оригинал: “https://dev.to/sourcemancer/easy-time-tracing-in-rxjava-and-reactor-2de4”