如何在Java中以同步方式处理异步回调?

我有一个与建筑相关的问题。这是一个与语言无关的问题,但是由于我来自Java背景,如果有人以Java的方式指导我,对我来说会更容易。

基本上,我正在编写的中间件与基于 SOAP 的第三方服务进行通信。调用是异步的 - 以某种方式,当调用服务时,它返回响应01 - 处理;表示第三方已成功收到请求。在原始 SOAP 请求中,每次都必须提交一个回调 URL,第三方实际发送结果。因此,调用特定服务实际上不会立即返回结果;结果在中间件的单独 HTTP 端点中接收。

现在在我们的前端,我们不想使用户体验复杂化。我们希望我们的用户调用中间件函数(通过菜单项/按钮),并立即获得结果;并将脏活的工作留给中间件。

请注意,从前端调用的中间件函数(假设 X())和第三方推送结果的中间件端点 URL(我们称之为 Y)是完全分开的。X() 必须以某种方式等待,然后获取在 Y 中抓取的结果,然后将结果返回到前端。

enter image description here

如何构建可靠的解决方案来实现上述行为?这张照片完美地描绘了我的情况。任何建议将不胜感激。


答案 1

这个问题可能更多地是关于集成模式,而不是关于多线程。但是,同一应用程序/JVM 中的请求可以使用异步调用和观察者模式的组合进行编排:

最好使用示例(利用您的Java知识)来完成此操作。检查以下尝试复制方案的简单组件:

第三方服务:它公开一个返回相关 ID 并启动长时间运行的执行的操作

class ExternalService {
    public String send() {
        return UUID.randomUUID().toString();
    }
}

面向客户的服务:它接收请求,调用第三方服务,然后在向结果接收方注册后等待响应:

class RequestProcessor {
    public Object submitRequest() {
        String correlationId = new ExternalService().send();

        return new ResultReceiver().register(correlationId).join();
    }
}

结果接收器:它向第三方服务公开操作,并维护内部关联注册表:

class ResultReceiver {

    Map<String, CompletableFuture<Object>> subscribers;

    CompletableFuture<Object> register(String responseId) {
        CompletableFuture<Object> future = new CompletableFuture<Object>();
        this.subscribers.put(responseId, future);

        return future;
    }

    public void externalResponse(String responseId, Object result) {
        this.subscribers.get(responseId).complete(result);
    }
}

在这种情况下,期货,承诺,回电都很方便。同步由初始请求处理器完成,以便强制执行为客户端阻止。

现在,这可能会引发许多在这个简单的类集中没有解决的问题。其中一些问题可能是:

  • 和 之间的争用条件。这是可以解决的问题,如果它没有,并且某些响应可以非常快(2路等待,可以这么说)new ExternalService().send()new ResultReceiver().register(correlationId)ResultReceiver
  • 永无止境的结果:结果可能花费太长时间或只是遇到错误。这些未来的 API 通常提供超时以强制取消请求。例如:

    new ResultReceiver().register(correlationId)
        .get(10000, TimeUnit.SECONDS);
    

答案 2

那么这样做到底有什么问题呢?您只需创建一个 API(中间件),在第三方返回处理后的结果之前,它不会返回响应。前端将请求发送到 X(),X() 通过向 Y() 发送请求来处理该请求,然后继续轮询 Y() 以查看结果何时准备就绪,然后 X() 从 Y() 获取结果并将其发送回前端。就像一个门面。

在使用第三方服务方面存在一些问题,您无法控制这些问题,您应该考虑这些问题。首先,您需要实现某种断路器或超时。因为第三方服务可能会挂起并且从不处理结果(或者处理结果的时间太长以至于等待是没有意义的)。此外,您应该考虑一些有意义的方法来保持站点运行,即使第三方服务不可用或已更新其API或其他原因阻止您使用它。

最后只是最后一个想法。为什么要使已经实现的东西异步同步?之所以这样制作,可能是因为它可能需要时间。长时间阻止前端等待结果会使用户体验不愉快,并且 UI 无响应。通常最好坚持异步请求并向用户展示他们正在处理的用户,但同时让他们做其他事情。


推荐