我有一个与架构有关的问题。这是一个与语言无关的问题,但是当我来自Java背景时,如果有人用Java方式引导我,对我来说会更容易。
基本上,我正在编写的中间件与基于SOAP的第三方服务进行通信。调用是异步的 - 在某种程度上,当一个服务被调用时,它返回一个响应01 - 处理;意味着第三方已成功收到请求。在原始SOAP请求中,每次都必须提交一个回调URL,其中第三方实际发送结果。因此,调用特定服务实际上不会立即返回结果;结果在中间件的单独HTTP端点中接收。
现在在我们的前端,我们不想让用户体验复杂化。我们希望我们的用户调用中间件功能(通过菜单项/按钮),并立即获得结果;并将肮脏的工作留给中间件。
请注意,从前端调用的中间件函数(比如说X())和第三方推送结果的中间件端点URL(让我们称之为Y)完全是彼此分开的。 X()不得不等待,然后获取在Y中抓取的结果,然后将结果返回到前端。
如何构建强大的解决方案来实现上述行为? 图片完美地描绘了我的情况。任何建议都将受到高度赞赏。
答案 0 :(得分:6)
这个问题可能更多地是关于集成模式而不是多线程。但是,可以使用异步调用和观察者模式的组合来编排同一应用程序/ 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);
}
}
在这种情况下,期货,承诺,回拨都很方便。同步由初始请求处理器完成,以强制执行阻止客户端。
现在,这可能引发一些在这个简单的类集中没有解决的问题。其中一些问题可能是:
new ExternalService().send()
和new ResultReceiver().register(correlationId)
之间的竞争条件。这是ResultReceiver
可以解决的问题,如果它没有表明某些响应可以非常快(双向等待,可以这么说)。永不落幕的结果:结果可能需要很长时间,或者只是遇到错误。这些未来的API通常会提供超时以强制取消请求。例如:
new ResultReceiver().register(correlationId)
.get(10000, TimeUnit.SECONDS);
答案 1 :(得分:1)
这样做究竟是什么问题?您只需创建一个API(中间件),在第三方返回处理结果之前不会返回响应。前端通过向Y()发送请求向X(),X()进程发送请求,然后继续轮询Y()以查看结果何时就绪,然后X()从Y()获取结果将它发送回前端。像一个门面。
使用您无法控制的第三方服务存在一些问题。首先,您需要实现某种断路器或超时。因为第三方服务可能会挂起并且永远不会处理结果(或者处理它们太长时间以至于没有意义等待)。此外,即使第三方服务不可用或已更新其API或其他阻止您使用它,您也应该考虑采用一些有意义的方式来保持网站正常运行。
最后只想到最后一个想法。为什么要创建已经实现异步同步的东西?这样做可能是因为它可能需要时间。长时间阻塞前端等待结果会使用户体验不愉快且UI无响应。通常最好坚持异步请求并显示他们正在处理的用户,但让他们同时做其他事情。