【问题标题】:reactive microprofile REST client blocks on QuarkusQuarkus 上的反应式微配置文件 REST 客户端块
【发布时间】:2021-02-05 08:06:04
【问题描述】:

在 Quarkus 上,我尝试使用动态 baseUrl 构建反应式微配置文件 REST 客户端,但到目前为止,在所有实现变体中,REST 调用在订阅后都会阻塞。有趣的是,非响应式实现就像一个魅力。让我们看一些代码...

REST 客户端接口:

package ...;

import io.smallrye.mutiny.Uni;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Response;
import java.io.InputStream;
import java.util.concurrent.CompletionStage;

import static javax.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM;

@Path("")
public interface RetrievalRestApi {

  @GET
  @Produces(APPLICATION_OCTET_STREAM)
  Uni<InputStream> retrieve();

  @GET
  @Produces(APPLICATION_OCTET_STREAM)
  InputStream retrieve2(); // non-reactive, the only one that works...

  @GET
  @Produces(APPLICATION_OCTET_STREAM)
  Uni<Response> retrieve3();

  @GET
  @Produces(APPLICATION_OCTET_STREAM)
  CompletionStage<InputStream> retrieve4();
}

Quarkus 测试:

package ...;

import io.quarkus.test.junit.QuarkusTest;
import io.smallrye.mutiny.Uni;
import org.apache.commons.io.IOUtils;
import org.eclipse.microprofile.rest.client.RestClientBuilder;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import javax.inject.Inject;
import javax.ws.rs.core.Response;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.function.Consumer;

import static org.junit.jupiter.api.Assertions.assertNotNull;

@QuarkusTest
class RetrievalRestApiTest {
  private URL restUrl;

  @BeforeEach
  void setUp() throws MalformedURLException {
    restUrl = new URL("https://some-valid-url");
  }

  @Test
  void testRetrieve() {
    Uni<InputStream> uni = RestClientBuilder.newBuilder()
                                            .baseUrl(restUrl)
                                            .build(RetrievalRestApi.class)
                                            .retrieve()
                                            .onFailure().invoke((Consumer<Throwable>) System.out::println);
    InputStream inputStream = uni.subscribe()
                                 .withSubscriber(UniAssertSubscriber.create())
                                 .await()
                                 .assertCompleted()
                                 .getItem();
    assertNotNull(inputStream);
  }

  @Test
  void testRetrieve2() throws IOException {
    InputStream inputStream = RestClientBuilder.newBuilder()
                                               .baseUrl(restUrl)
                                               .build(RetrievalRestApi.class)
                                               .retrieve2();
    assertNotNull(inputStream);
    String content = IOUtils.toString(inputStream, StandardCharsets.UTF_8);
    assertNotNull(content);
  }

  @Test
  void testRetrieve3() {
    Uni<Response> uni = RestClientBuilder.newBuilder()
                                         .baseUrl(restUrl)
                                         .build(RetrievalRestApi.class)
                                         .retrieve3()
                                         .onFailure().invoke((Consumer<Throwable>) System.out::println);
    Response response = uni.subscribe()
                                 .withSubscriber(UniAssertSubscriber.create())
                                 .await()
                                 .assertCompleted()
                                 .getItem();
    assertNotNull(response);
  }

  @Test
  void testRetrieve4() {
    Uni<InputStream> uni = Uni.createFrom().completionStage(RestClientBuilder.newBuilder()
                                         .baseUrl(restUrl)
                                         .build(RetrievalRestApi.class)
                                         .retrieve4())
                                         .onFailure().invoke((Consumer<Throwable>) System.out::println);
    InputStream inputStream = uni.subscribe()
                                 .withSubscriber(UniAssertSubscriber.create())
                                 .await()
                                 .assertCompleted()
                                 .getItem();
    assertNotNull(inputStream);
  }
}

在运行 4 个测试时,只有使用非反应式 API 的 testRetrieve2 是成功的。所有其他人都挂在 AssertSubscriber.await() 中。

有什么想法吗?

【问题讨论】:

  • 问题似乎与使用 Quarkus Jaeger 进行跟踪有关。一旦我使用quarkus.jaeger.enabled=false 禁用跟踪,就不再有阻塞。也许它与github.com/quarkusio/quarkus/issues/13440 有关,因为我看到几乎相同的堆栈跟踪(差异可能是由于不同的 Quarkus 版本)。

标签: java quarkus microprofile mutiny


【解决方案1】:

问题确实与https://github.com/quarkusio/quarkus/issues/13440有关。将 Quarkus 升级到 1.12.0.Final 后问题消失了。

【讨论】:

    猜你喜欢
    • 2023-02-14
    • 2020-06-19
    • 2020-02-15
    • 1970-01-01
    • 2021-12-17
    • 2022-01-08
    • 1970-01-01
    • 2022-07-14
    • 2011-10-13
    相关资源
    最近更新 更多