我正在做一个Sping Boot 项目,我必须公开一个API,它会触发一个耗时超过5分钟的长处理。这是我的API:
@GetMapping("/print")
public ResponseEntity<String> print() {
// Call External API One to get data & process
// Call External API Two to get data & process
// Call External API Tree get data & process
// Call internal Service to Update database
// this API takes more than 5min
return new ResponseEntity<>("Ok..", HttpStatus.OK);
}
这个端点将被一个批处理调用,我们不想让这个批处理等待来自这个端点的响应很长时间,也避免了超时问题。
你有什么想法的最佳实践和范例,我可以实现开发这个API?
谢谢
2条答案
按热度按时间lnlaulya1#
这是异步服务的典型场景。基本思想是,当你有一个长时间运行的任务时,你只需向客户端确认,该请求已被接收,并返回一些任务ID作为你的确认响应的一部分。使用这个id客户端将知道在结果到达时要查找什么。同时,服务器执行任务,并将结果写入与客户端相互约定的某个通道,通常是一个队列,有时是DB。客户端侦听该通道,当具有该id的消息到达该通道时,客户端读取该消息。这样,客户端就不必在整个处理时间内在线等待。
92dk7w1h2#
如果你的目标是重新设计一个API(而不是实现),以这种方式,没有API方法执行很长一段时间,那么有两种常见的方法:
第一个方法应该在后台开始执行,并返回分配给调用的生成的标识符。例如,它可以是
UUID.randomUUID()
或递增计数器。在计数器的情况下,确保线程安全,考虑AtomicLong
。使用ThreadPool
/Executors
执行后台,并获取Future
是最常见的选择。第二种方法将identifier作为参数,检查计算是否完成,并返回“尚未完成”信号或计算响应。作为“未完成”信号,您可以使用例如
204 No Content
HTTP代码。要实现这种方法,您必须跟踪已执行的后台计算和分配给它们的id。注意,以线程安全的方式存储<id,Future> map。不要忘记在一段时间后和/或检索后删除旧条目。显然,该解决方案仅适用于单个服务器示例。
很少使用。您可以将URL作为参数传递,立即从方法返回,并在计算完成后将计算的数据POST到保存的URL。
此外,您可能可以通过并行调用API 1,2和3来显着提高您的实现,因为它们不相关。考虑使用
WebClient
,它是异步的,不需要每个调用都有专门的线程。