【问题标题】:Interrupt if API call to payment processor takes over 60 seconds如果对支付处理器的 API 调用超过 60 秒,则中断
【发布时间】:2019-04-09 17:59:48
【问题描述】:

我正在与支付处理器集成,并试图处理以下情况:

  • 用户点击支付并向我们的服务器发出请求
  • 我们的服务器向支付处理器发出请求
  • 付款处理方出现明显延迟
  • 在某个阈值之后,例如60 秒后,我们会提醒用户付款失败
  • 70 秒后,支付处理器返回成功响应。

所以我需要从 UI 的 HTTP 调用中启动对支付处理器的 API 调用,然后如果需要超过 60 秒,则结束 HTTP 调用并向用户返回错误,然后如果 API 调用支付处理器最终成功(比如 70 秒后),向管理团队发送电子邮件。

我在想这样的事情:

    import javax.ws.rs.client.*;
    import java.util.Timer;
    import java.util.TimerTask;

    ...

    boolean overThreshold = false;
    int timeout = 60; // seconds
    TimerTask task = new TimerTask() {
        @Override
        public void run() {
            overThreshold = true;
            // return a message to user here saying their payment could not be processed
        }
    };

    new Timer(true).schedule(task, timeout * 1000);

    Client client = ClientBuilder.newClient();
    WebTarget webTarget
            = client.target({url of payment processor});
    Invocation.Builder builder = webTarget.request()
            .header(HttpHeaders.CONTENT_TYPE, APPLICATION_JSON);

    final Response response = builder.post(Entity.json(new Gson().toJson(request)));

    if (overThreshold) {
        // send alert email here
    }

有一些问题,例如run() 方法的返回值是 void,从内部类访问 overThreshold 时出错。有没有更优雅的方式来做到这一点?

【问题讨论】:

  • IMO,它是作为响应式服务实现的经典用例。您可能对类似于 blog.payara.fish/… 的内容感兴趣

标签: java multithreading jersey thread-safety


【解决方案1】:

ExecutorService 使用Future.get(timeout) 应该可以非常干净地处理这个问题。

例如:

    ExecutorService executor = Executors.newCachedThreadPool();

    // ... set up builder as before ...
    Future<Response> responseFuture = executor.submit(
            () -> builder.post(Entity.json(new Gson().toJson(request))));
    try {
        Response response = responseFuture.get(timeout, TimeUnit.SECONDS);
        // return normal response here
    } catch (TimeoutException ex) {
        executor.submit( () -> {
            Response lateResponse = responseFuture.get();
            // send overThreshold alert email here
            // Dummy return - prefer Callable to Runnable here for exception handling
            return null;
        } );
        // return a message to user here saying their payment could not be processed
    }

ExecutorService 的选择可以调整为适合,或者同样是应用程序中其他地方的共享线程池。

【讨论】:

  • 实际上,只是实现这一点——如果我向用户返回一条消息,那么response = responseFuture.get(); 将永远不会被执行...
  • 好点。如果直接return消息(而不是写入响应流),最简单的方法是使后续异步。等待get() 和随后发送的 overThreshold 警报可以在它们准备好时发生。答案已在这些行中更新。另一种可能性是重新检查在builder.post() 之后的第一个块中是否发回了响应。这对于失败情况下的线程计数更有效,但需要更多的共享状态和/或同步来在两个线程之间进行通信。
  • 是否可以在jdk中通过CompletableFuture完成你提供的代码的逻辑,我试过但找不到办法
猜你喜欢
  • 2023-03-18
  • 2016-02-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-05
  • 2014-12-22
相关资源
最近更新 更多