【问题标题】:Play Framework 2.4 Sequential run of multiple PromisesPlay Framework 2.4 多个Promises的顺序运行
【发布时间】:2016-04-18 17:45:12
【问题描述】:

我有一个 Play 2.4(基于 Java)的应用程序,其中一些后台 Akka 任务实现为返回 Promise 的函数。

  • Task1 通过银行 Rest API 下载银行对账单。
  • Task2 处理报表并将它们与客户配对。
  • Task3 执行一些其他处理。

Task2 在 Task1 完成其工作之前无法运行。 Task3 不能在 Task2 之前运行。我试图通过Promise.map() 序列来运行它们,如下所示:

protected F.Promise run() throws WebServiceException {
        return bankAPI.downloadBankStatements().map(
                result -> bankProc.processBankStatements().map(
                        _result -> accounting.checkCustomersBalance()));
}

我的印象是,第一张地图会等到 Task1 完成,然后它会调用 Task2,依此类推。当我查看应用程序(任务正在将一些调试信息写入日志)时,我可以看到,这些任务是并行运行的。

我也尝试使用Promise.flatMap()Promise.sequence(),但没有成功。任务始终并行运行。

我知道 Play 本质上是非阻塞应用程序,但在这种情况下,我真的需要按正确的顺序做事。

关于如何按选定的顺序运行多个 Promise 有什么通用的做法吗?

【问题讨论】:

    标签: akka playframework-2.4


    【解决方案1】:

    您将第二次调用嵌套到map,这意味着这里发生的事情是

    1. processBankStatements
    2. 检查客户余额
    3. 下载银行对账单

    相反,您需要将它们链接起来:

    protected F.Promise run() throws WebServiceException {
        return bankAPI.downloadBankStatements()
                      .map(statements -> bankProc.processBankStatements())
                      .map(processedStatements -> accounting.checkCustomersBalance());
    }
    

    我注意到您没有使用 result_result(为了清楚起见,我已将其重命名)- 这是故意的吗?

    【讨论】:

    • 好吧,我使用的是F.Promise.promise(lambda),它由processBankStatementscheckCustomerBalance 返回。 Promise 不能有 void 结果类型,所以我从 Promise 返回 null。所以结果无关紧要。所有三个函数/承诺都在做一些数据库工作,它们不返回任何东西。唯一的目的是以选定的顺序运行这些作业。我知道这不是一个很好的方法,也不是很好地使用 Play 功能,但在这种情况下它是必要的。无论如何感谢您的建议。我会试试的。
    • 如果不需要返回值也没关系,我只是在检查答案是否完整。
    • 好吧,它不起作用。现在所有三个 Promise 都是并行启动的。
    • 你怎么知道的?记录,还是别的什么?我建议在 lambdas 中使用断点来确定执行顺序。
    • 我在日志中看到了这个。它在数据处理中也是可见的。例如,第一次运行时,下载了 10 份银行对账单,处理了 0 份(应该是 10 份)。在下一次运行中,将下载更多 20 份银行对账单,其中 10 份得到处理。下一次运行 5 被下载,20 被处理。似乎一旦运行了第 2 个承诺,它就看不到新的最近银行对帐单,因为它们当时不存在于数据库中。相反,它会看到以前下载的项目。在日志中,我看到所有三个任务同时开始,并根据任务持续时间看到不同的结束时间。
    【解决方案2】:

    好的,我找到了解决方案。正确答案是:

    如果您以我的方式链接多个 Promise。这意味着,作为 map() 函数的回报,您期待另一个 Promise.map() 函数等等,您应该遵循以下规则:

    • 如果您从映射返回非期货,只需使用map()
    • 如果您从映射返回更多期货,您应该使用flatMap()

    我的情况下正确的代码 sn-p 是:

    return bankAPI.downloadBankStatements().flatMap(result -> {
            return bankProc.processBankStatements().flatMap(_result -> {
                return accounting.checkCustomersBalance().map(__result -> {
                    return null;
                });
            });
    });
    

    这个解决方案是很久以前向我提出的,但一开始并不奏效。问题是,我有一个隐藏的 Promise.map() 内部函数 downloadBankStatements() 所以在这种情况下 flatMaps 链被破坏了。

    【讨论】:

    • 这个答案的灵感来自here
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-08
    • 2015-08-16
    • 1970-01-01
    • 2016-07-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多