运行 一项长期的 运行 工作,在 Reactor 和 r2dbc 中使用 Thymeleaf 的即发即弃策略

Run a long running job using the fire and forget strategy with Thymeleaf in Reactor and r2dbc

我正在尝试使用 webflux、thymeleaf 和 r2dbc 来实现一劳永逸的效果。我有两个端点,一个用于添加员工,另一个用于列出所有员工。我想模拟一个缓慢的数据库访问,所以在我调用数据库之前我有几秒钟的线程休眠。

现在,我希望在调用 /add 时看到的效果是我的控制器立即 return 并且页面 add 立即呈现。但是,我不确定如何实现这一目标。使用当前代码 nap() 发生在我可以 return 一个 Mono 之前。换句话说,我正在尝试 运行 在后台进行长时间的 运行ning 作业而不阻塞控制器。

我有以下型号:

@Data
public class Employee {
    @Id
    private Long id;
    private String name;
}

带注释的控制器有以下方法:

@GetMapping(value = "/")
public String home(Model model) {
    model.addAttribute("employees", repo.findAll());
    return "home";
}

@GetMapping(value = "/add")
public Mono<String> add() {
    return Mono
        .defer(this::getEmployee)
        .doOnNext(e -> repo.save(e).subscribe())
        .thenReturn("add");
}

private Mono<Employee> getEmployee() {
    final var e = new Employee();
    e.setName("John");
    nap(); // calls thread sleep for a few sec
    return Mono.just(e);
}

我的问题是如何包装冗长的 运行ning 作业,同时保留基于控制器的符号(而不是功能性符号)并立即呈现 add 页面?我知道一些类似的问题,例如 and ,但我似乎无法实现我需要的行为。

编辑: lkatiforis 的建议和 this SO 问题是朝着正确方向的推动。我不得不稍微调整他们的例子,因为员工没有坚持。更改在 add():

public String add() {
    Mono.just(employee)
        .delayElement(Duration.ofSeconds(5))
        .doOnNext(e -> repo.save(e).subscribe())
        .subscribe();
    return "add";
}

employee 只是具有填充名称的 Employee 的一个实例。 delayElement 运算符暂停 5 秒而不阻塞。最后,我不得不在 repo.save() 上调用 subscribe() 并在最后调用它才能正常工作。我假设如果 subscribe() 只在 doOnNext() 上被调用,那么以 Mono.just() 开头的主链永远不会被执行。

我猜 nap() 方法执行 Thread.sleep 或类似的东西,对吧? Thread.sleep 正在阻塞主线程,使应用程序无响应。您可以使用 delayElements 运算符来模拟长 - 运行 操作:

private Mono<Employee> getEmployee() {
    final var e = new Employee();
    e.setName("John");
    return Mono.just(e).delayElement(Duration.ofSeconds(5));
}