首页 > 解决方案 > 允许 Spring REST 方法调用异步方法而不等待响应

问题描述

假设我有一个方法foo(),每天晚上凌晨 3 点在后端执行大约需要 30 分钟。

在传统意义上,我们可以使用 Spring Scheduler 和 cron 注解:

@Scheduled(cron = "0 0 3 ? * *")
public void foo() {
    ...
}

不幸的是,由于项目负责人对使用 Spring Scheduler 而不是企业调度工具持保留意见,因此我无法使用此解决方案。

在这种情况下,我们所拥有的是调度工具命中以下方法的 REST 端点。

@RequestMapping(value = "/foo", method = RequestMethod.Post)
public ResponseEntity<Boolean> doFoo() {
    foo(); //goal is to make this not hold up the return statement

    return ResponseEntity.ok(true);
}

有没有办法让 foo 异步执行而不等待一个完整的未来?foo()无论它需要多长时间,它都应该继续自行关闭,并且 curl 响应应该几乎是立即的。

标签: springrestasynchronous

解决方案


有没有办法让foo()异步执行而不等待一个完整的未来?

foo()您可以在 Spring Bean 中定义该方法。由于您似乎对任何返回值不感兴趣,因此您可以将void其用作返回类型。foo()然后用注释@Async

@Service
public class FooService {

    @Async
    public void foo() {
        ...
    }
}

你还需要确保你有@EnableAsync一个配置类:

@EnableAsync
@Configuration
public class AsyncConfig {

}

foo()然后您可以从控制器方法调用:

@RequiredArgsConstructor
@RequestMapping(value = "/foo")
public class FooController {

    private final FooService fooService;

    @PostMapping
    public ResponseEntity<Boolean> doFoo() {
        fooService.foo();
        return ResponseEntity.ok(true);
    }
}

而且,如果需要,您还可以调用foo()from @Scheduled-annotated 方法:

@Scheduled(cron = "0 0 3 ? * *")
public void foo() {
    fooService.foo();
}

让我强调一下,这202将是比200这种情况更准确的状态代码:

6.3.3. 202 接受

( 202Accepted) 状态码表示请求已被接受处理,但处理尚未完成。该请求最终可能会或可能不会被执行,因为在实际进行处理时它可能会被禁止。HTTP 中没有用于从异步操作重新发送状态代码的工具。

202回应是故意不置可否。它的目的是允许服务器接受对其他进程的请求(可能是一个每天只运行一次的面向批处理的进程),而不需要用户代理与服务器的连接持续到进程完成。与此响应一起发送的表示应该描述请求的当前状态并指向(或嵌入)一个状态监视器,该监视器可以为用户提供对何时完成请求的估计。


推荐阅读