【问题标题】:Making asynchronous HTTP calls from flows从流中进行异步 HTTP 调用
【发布时间】:2018-05-21 20:42:57
【问题描述】:

在 Corda 中,如何从流中发出异步 HTTP 请求?是否有 API 可以在等待 HTTP 调用的响应时暂停流,或者提供回调的方法?

【问题讨论】:

    标签: corda


    【解决方案1】:

    Corda 目前不提供一种机制来发出异步 HTTP 请求,然后在等待响应时暂停流,或提供将在收到响应时调用的回调。

    相反,建议您在启动流之前发出 HTTP 请求,然后在实例化流时将响应作为参数传入。

    有时,这是不可能的。例如,自动启动的响应流可能需要 HTTP 请求,也可能取决于从对方收到的消息的内容。

    在这种情况下,您仍然可以支持这种工作流程,如下所示。假设您正在为贷款申请编写一个 CorDapp,表示为 LoanApplicationStates。如果没有 HTTP 调用,响应者不知道是否接受贷款申请。

    流程将创建一个UnacceptedLoanApplicationState,而不是直接创建LoanApplicationState,响应者将其存储在他们的分类帐中。一旦流程结束,响应者可以在流程框架之外进行 HTTP 调用。根据 HTTP 调用的结果,响应者将启动创建事务以将 UnacceptedLoanApplicationState 转换为 LoanApplicationState 的批准流程,或者启动拒绝流程以使用 UnacceptedLoanApplicationState 状态而不发出接受LoanApplicationState

    或者,您可以向LoanApplicationState 添加一个状态字段,指定贷款是否被批准。最初,贷款状态将字段设置为未批准。然后,根据 HTTP 请求的结果,响应者将启动两个流程之一来更新 LoanApplicationState,将其更新为已批准或已拒绝状态。

    【讨论】:

    • 在您的 Loan 示例中,Corda 客户端如何知道有一个新的 UnacceptedLoanApplicationState,以便它可以进行 http 调用并为 LoanApplicationState 调用新流程?
    • 您可以在服务器端使用CordaRPCOps.vaultTrackBy 来检查何时注册了新的未接受的贷款申请。
    • 谢谢@Joel,再问一个问题,异步调用是不可能的,但是同步调用是可能的,对吧?如果是,我们是否可以在收到 LoanApplication 后调用其他流程,即接受或拒绝流程。但这种方法的疑问是,其他流程将失败,因为 LoanApplication 尚未提交,它应该作为输入出现..
    • 这是一个有趣的竞争条件问题。可以单独养吗?
    【解决方案2】:

    Corda 使用quasar fibers 进行类似同步(异步)的调用。幸运的是,quasar 支持java's Futureguava's ListenableFuture

    基于此,您可以创建一个这样的流

    @InitiatingFlow
    class ListenableFutureFlow<V>(val futureFn: () -> ListenableFuture<V>,
                                  override val progressTracker: ProgressTracker) : FlowLogic<V>() {
    
        constructor(futureFn: () -> ListenableFuture<V>) : this(futureFn, tracker())
    
        companion object {
            object EXECUTING_FUTURE: ProgressTracker.Step("Executing future call inside fiber")
            fun tracker() = ProgressTracker(EXECUTING_FUTURE)
        }
    
        @Suspendable
        override fun call(): V {
            progressTracker.currentStep = EXECUTING_FUTURE
            return AsyncListenableFuture.get(futureFn())
        }
    }
    

    你可以这样使用它:

    val asyncResponse = subFlow(ListenableFutureFlow { myAsyncCall(param1, param2) })
    

    这不是最好的解决方案,但至少可以与 corda 的基础架构一起使用 :)

    让我知道它是否适合你!

    【讨论】:

    • 有意思,所以这个方法会挂起当前的 Fiber 并在未来解决时唤醒它?
    • 还应注意,这种方法会泄漏线程本地资源...例如数据库连接。
    猜你喜欢
    • 1970-01-01
    • 2016-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-28
    • 2019-01-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多