【问题标题】:quarkus: IllegalStateException: You have attempted to perform a blocking operation on a IO thread. This is not allowed, as blocking the IO threadquarkus: IllegalStateException: 您试图在 IO 线程上执行阻塞操作。这是不允许的,因为阻塞了 IO 线程
【发布时间】:2020-05-21 12:13:57
【问题描述】:

对于 quarkus,我无法理解一件事。 我将 JPA 与 Oracle 一起使用。所以我有错误 IllegalStateException:您试图在 IO 线程上执行阻塞操作。这是不允许的,因为阻塞了 IO 线程 我查看了 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 中使用,因为它会引发异常。因此必须将其捕获。但是后来我们不再进入 Uni 的 onFailure 并且我们无法追踪我们捕获的错误。

我认为我想太多关于使用我的命令式代码而不是不同的想法。

但无论如何我都找不到像这样的文档或示例。我想有一种做事的方式(如果不是 Quarkus 就不会存在)。我认为当你用正确的方法考虑它时,你必须找到文档,但是当你不知道去哪里时,它就更复杂了。我没有找到它,因为我不知道我在寻找什么。

我想我必须封装产生 Uni 或 Multi 的 JPA 调用,该调用由将实体转换为 DTO 的处理器消耗,然后将其传输到将 DTO 转换为响应的资源 Rest 层。 JPA 调用必须能够在处理器和资源层也产生错误

因此,有必要在每个步骤中捕获这些错误以通过 Uni 或 Multi 传播它们

但是怎么做呢?

【问题讨论】:

    标签: java quarkus reactive-streams mutiny


    【解决方案1】:

    通过简单地提供 lambda 实现(或方法引用)作为方法调用参数,这是一种已知的 lambda 限制.

    同时,可以通过围绕预期的功能接口实现扩展来简单地解决它,在您的情况下,它将是Supplier<T>,它将捕获任何**已检查**异常并抛出一个unchecked

    /**
     * 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 类型对象的方法

    然后,您可以在需要Supplier&lt;T&gt;(或类似名称)的任何地方使用显式cast 来使用新的CheckedSupplier 接口:

    Uni.createFrom().item((CheckedSupplier<DataType>) MutinyTest::findOne)
          .onItem()
          .apply(i-> Response.ok(i))
          .onFailure()
          .apply(e-> Response.status(555, e.getMessage()));
    

    【讨论】:

    • 哦,谢谢我如此专注于我的反应式编程问题,以至于我从未想过将错误包装在 runtimeException 中
    • 不客气,如果有助于解决问题,请毫不犹豫地投票并接受答案;)
    【解决方案2】:

    我更改了 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())
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-25
      • 1970-01-01
      相关资源
      最近更新 更多