quarkus: IllegalStateException: вы попытались выполнить операцию блокировки в потоке ввода-вывода. Это недопустимо, так как блокирование потока ввода-вывода
Есть одна вещь, которую я не могу понять с кваркусом. Я использую JPA с Oracle. Итак, у меня ошибка IllegalStateException: вы попытались выполнить операцию блокировки в потоке ввода-вывода. Это недопустимо, так как блокирование потока ввода-вывода я посмотрел в документации Quarkus, как выполнять вызовы JPA без этой проблемы. Но все примеры и документы используют PostgreSQL или MariaDB с отзывчивыми клиентами. Но для классических клиентов JDBC я не нашел.
Я нашел решение, которое работает частично.
Uni.cretaFrom().Items(() -> MyBlokingIOCall());
На самом деле для меня больше нет исключения. Но метод MyBlokingIOCall может вызывать исключения. Я думаю, что могу использовать Uni onFailure, но мы не можем передавать методы, вызывающие исключение, в
Uni.cretaFrom().Items
На самом деле этот метод имеет в качестве аргумента поставщика, поэтому исключения должны быть зафиксированы. с этим решением невозможно использовать Uni onFailure. Если я использую текущий код в императивном режиме
try {
Response.ok (myService ());
} catch (throwable e) {
Response.status (555, e.getMessage ());
}
Я тщетно пытался сделать это в реактивной форме, но решения не нашел. Никакой помощи не нашел. Я представил себе что-то подобное.
Uni.createFrom().Items(() -> myService())
.onItem().apply(data -> Response.ok(data))
.onFailure().apply(err -> Response.status(555, err.getMessage()))
Но это вызывает ошибку компиляции. действительно, метод myService нельзя использовать в Supplier, потому что он генерирует исключение. поэтому он должен быть захвачен. Но тогда мы больше не входим в onFailure Uni и не можем отследить обнаруженную ошибку.
Я думаю, что слишком много думаю о том, чтобы использовать свой императивный код вместо того, чтобы думать иначе.
Но я никак не могу найти документ или пример, который бы выглядел так. Я полагаю, что есть способ делать что-то (если бы не Quarkus, не существовало бы). Я думаю, что когда вы думаете об этом с правильным подходом, вам нужно найти документ, но когда вы не знаете, куда идти, все сложнее. Я не нашел, потому что не знаю, что ищу.
Я предполагаю, что мне нужно инкапсулировать вызов JPA, который создает Uni или Multi, который потребляется процессором, который преобразует Entity в DTO, который затем передается на уровень Rest ресурсов, который преобразует DTO в Response. вызов JPA должен иметь возможность создавать ошибки, как процессор, так и уровень ресурсов тоже
Следовательно, необходимо на каждом этапе фиксировать эти ошибки, чтобы распространять их через Uni или Multi
Но как это сделать?
2 ответа
Это своего рода известное ограничение лямбда, когда дело доходит до краткости и первых ожиданий, просто предоставляя реализацию лямбда (или ссылку на метод) в качестве параметра вызова метода.
Между тем, это можно просто обойти, реализовав расширение вокруг ожидаемого функционального интерфейса, в вашем случае это будетSupplier<T>
, который перехватит любое ** проверенное ** исключение и выдаст непроверенное:
/**
* A Supplier sub-interface that catches any thrown exception
* and translates to an unchecked one.
*
* <p>This is a functional interface whose functional method is
* {@link #getChecked()}.
*/
@FunctionalInterface
public interface CheckedSupplier<T> extends Supplier<T> {
@Override
default T get() {
try {
return getChecked();
} catch (final Exception e) {
// Your common exception handling logic here..
throw new RuntimeException(e);
}
}
/**
* Gets a result.
*
* @return a result
* @throws Exception
*/
T getChecked() throws Exception;
}
Обратите внимание, что подпись функционального интерфейса больше не #get(), а #getChecked(). Но это не повлияет на компилятор, который попытается проверить функциональную сигнатуру на основе ожидаемой, а именно:
метод, возвращающий объект типа T
Тогда вы можете просто использовать новый CheckedSupplier
интерфейс, используя только явное приведение везде, гдеSupplier<T>
(или подобное) ожидается:
Uni.createFrom().item((CheckedSupplier<DataType>) MutinyTest::findOne)
.onItem()
.apply(i-> Response.ok(i))
.onFailure()
.apply(e-> Response.status(555, e.getMessage()));
Я изменил свой метод myService, чтобы он возвращал поставщика и обрабатывал исключения.
public Supplier<List<String>> myService (String arg){
return () -> {
try {
//my code
return result;
} catch (Exception e) {
throw new RuntimeException(e);
}
};
}
и я назвал это так
Uni.createFrom().item(myService("sample")))
.onItem().apply(data -> Response.ok(data))
.onFailure().recoverWithItem(err -> Response.status(600, err.getMessage()))
.onItem().apply(ResponseBuilder::build)
.emitOn(Infrastructure.getDefaultExecutor())