关闭异步 resteasy 客户端调用的最佳方法

Ser*_*kan 6 resteasy quarkus

我有以下代码:

var threadsWaiter = new CountDownLatch(customers.size());
for(var c: List<Customer> customers) {
   sendSms(c.phoneNr, threadsWaiter)
}
threadsWaiter.await();

public void sendSms(String phoneNr, CountDownLatch threadsWaiter) {
  ResteasyClientBuilder.newClient()
            .target(smsUrl)                
            .queryParam("to", phoneNr)
            .queryParam("message", message)
            .request()
            .async()
            .get(new InvocationCallback<String>() {
                @Override
                public void completed(String res) {
                    threadsWaiter.countDown();
                    if (res != null && !res.contains("code=ok") {
                        logger.error("Received sms response for '{}'\n{}", phoneNr, res);
                    } else {                            
                        logger.debug("Sms sent to '{}'", phoneNr);
                    }
                }

                @Override
                public void failed(Throwable throwable) {
                    threadsWaiter.countDown();
                    logger.error("Error sending sms for {}: \n{}", phoneNr, throwable.getMessage());
                }
            });
}
Run Code Online (Sandbox Code Playgroud)

我从控制台收到以下警告:

RESTEASY004687: Closing a class org.jboss.resteasy.client.jaxrs.engines.ApacheHttpClient43Engine instance for you. Please close clients yourself.

关闭此客户端调用的正确方法是什么?因为这可能是应用程序中潜在内存泄漏的来源。甚至我从 RestEasy 收到了这个警告,它会自动为我关闭客户端,但我有一种强烈的感觉,它不会关闭所有客户端,因为我看到指标中的内存大幅增加,这不会“去下来”一段时间后。

我已经在 try-finally 之间放置了其余的客户端调用,但问题在于您可以在调用完成之前关闭客户端。可以关闭InvocationCallback 中的客户端completed(..)和failed(..)方法,还是有更好的方法?

Oli*_*idt 1

使用 Quarkus 执行此操作的最佳方法是使用具有异步支持的 REST 客户端。例子:

    /**
     * This is the client stub.
     */
    @Path("/sms/response") // base URL is set in application.yml
    @RegisterRestClient
    public interface SmsServiceClient {
        
        @GET
        @Produces(MediaType.TEXT_PLAIN)
        CompletionStage<String> sendSms(
            @QueryParam("to") String phoneNr,
            @QueryParam("message") String message);
    }
Run Code Online (Sandbox Code Playgroud)

在下面的示例中,我使用SmallRye Mutiny将 转换CompletionStage为Uni具有更精简 API 的 。但您可以使用CompletionStage. 通常,我不会用该CountDownLatch.await()方法阻止执行。我把它放在那里是为了保持代码与您的示例相似。

    /**
     * This class will actually use the client.
     */
    @Slf4J
    @ApplicationScoped
    public class MySomething {
        
        @Inject
        @RestClient
        SmsServiceClient smsClient;

        public void sendSmsInLoop() {
            var waiter = new CountDownLatch(customers.size());
            customers.forEach(customer -> {
                Uni.createFrom().completionStage(
                    smsClient.sendSms(customer.getPhoneNr(), "Lorem Ipsum...")
                ).onItem().invoke(responseString -> {
                    if (responseString == null || !responseString.contains("code=ok")) {
                        log.error("Unexpected sms response for '{}'\n{}", customer.getPhoneNr(), responseString); 
                    } else {
                        log.debug("Sms sent to '{}'", customer.getPhoneNr());
                    }
                }).onFailure().invoke(throwable -> {
                    log.error("Error sending sms to '{}'\n{}", customer.getPhoneNr(), throwable.getMessage());
                }).eventually(() -> waiter.countDown());
            });
            waiter.await();
        }
    }
Run Code Online (Sandbox Code Playgroud)