关闭异步 resteasy 客户端调用的最佳方法
Posted
技术标签:
【中文标题】关闭异步 resteasy 客户端调用的最佳方法【英文标题】:Best way to close async resteasy client call 【发布时间】:2020-05-14 09:22:43 【问题描述】:我有以下代码:
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());
);
我从控制台收到以下警告:
RESTEASY004687: Closing a class org.jboss.resteasy.client.jaxrs.engines.ApacheHttpClient43Engine instance for you. Please close clients yourself.
关闭此客户呼叫的正确方法是什么?因为这可能是应用程序中潜在内存泄漏的来源。甚至我从 RestEasy 收到警告,它会自动为我关闭客户端,但我有一种强烈的感觉,它不会关闭所有客户端,因为我看到指标中的内存大幅增加,而且这不会“去一段时间后“下来”。
我已经在 try-finally 之间放置了其余的客户端调用,但这样做的问题是您可以在调用完成之前关闭客户端。 InvocationCallback 中的completed(..)
和failed(..)
方法中关闭客户端是否可以,还是有更好的方法?
【问题讨论】:
【参考方案1】:如果通过 JaxRS 接口的客户端定义对您来说没问题,那么上面rowing-goul 的答案就是要走的路。 Quarkus Arc 在 bean 销毁过程中自动关闭注入的客户端。如果您手动创建客户端,则必须明确关闭它们 - 最好的方法是 try - finally
【讨论】:
【参考方案2】:使用 Quarkus 执行此操作的最佳方法是使用 REST client with async support。 示例:
/**
* 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);
在以下示例中,我使用SmallRye Mutiny 将CompletionStage
转换为具有更精简API 的Uni
。但是您可以使用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();
【讨论】:
以上是关于关闭异步 resteasy 客户端调用的最佳方法的主要内容,如果未能解决你的问题,请参考以下文章
创建 web 应用程序的最佳方法,该应用程序在外部客户端调用他自己的休息服务时动态更新 UI [关闭]