Spring长时间加工API的最佳解决方案

utugiqy6  于 2023-06-21  发布在  Spring
关注(0)|答案(2)|浏览(107)

我正在做一个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?
谢谢

lnlaulya

lnlaulya1#

这是异步服务的典型场景。基本思想是,当你有一个长时间运行的任务时,你只需向客户端确认,该请求已被接收,并返回一些任务ID作为你的确认响应的一部分。使用这个id客户端将知道在结果到达时要查找什么。同时,服务器执行任务,并将结果写入与客户端相互约定的某个通道,通常是一个队列,有时是DB。客户端侦听该通道,当具有该id的消息到达该通道时,客户端读取该消息。这样,客户端就不必在整个处理时间内在线等待。

92dk7w1h

92dk7w1h2#

如果你的目标是重新设计一个API(而不是实现),以这种方式,没有API方法执行很长一段时间,那么有两种常见的方法:

    • 1.拆分API方法为“开始执行”(POST)和“检查结果”(GET)**

第一个方法应该在后台开始执行,并返回分配给调用的生成的标识符。例如,它可以是UUID.randomUUID()或递增计数器。在计数器的情况下,确保线程安全,考虑AtomicLong。使用ThreadPool/Executors执行后台,并获取Future是最常见的选择。
第二种方法将identifier作为参数,检查计算是否完成,并返回“尚未完成”信号或计算响应。作为“未完成”信号,您可以使用例如204 No Content HTTP代码。
要实现这种方法,您必须跟踪已执行的后台计算和分配给它们的id。注意,以线程安全的方式存储<id,Future> map。不要忘记在一段时间后和/或检索后删除旧条目。显然,该解决方案仅适用于单个服务器示例。

    • 2.传入回调url作为参数**

很少使用。您可以将URL作为参数传递,立即从方法返回,并在计算完成后将计算的数据POST到保存的URL。
此外,您可能可以通过并行调用API 1,2和3来显着提高您的实现,因为它们不相关。考虑使用WebClient,它是异步的,不需要每个调用都有专门的线程。

相关问题