R3 Corda: 升級 CorDapp(非平臺版本升級)- Flow 版本

原文地址:https://docs.corda.net/upgrading-cordapps.html#flow-versioning

任何初始化其他 flows 的 flow 必須要使用 @InitiatingFlow 注解,像下邊這樣定義:

annotation class InitiatingFlow(val version: Int = 1)

version 屬性默認值為1,定義了 flow 的版本。當(dāng)flow 有任何一個新的 release 的時候并且這個 release 包含的變動是非向下兼容的,這個數(shù)值應(yīng)該增加。一個非向下兼容的改動是一個改變了 flow 的接口的變動。

Flow 的接口是如何定義的?

Flow 的接口是通過在 InitiatingFlowInitiatedBy flow 之間有序的 sendreceive 調(diào)用來定義的,包括發(fā)送和接受的數(shù)據(jù)的類型。我們可以將 flow 的接口如下圖這樣表示:

Flow 接口

在上邊的圖中,InitiatingFlow

  • 發(fā)送了一個 Int
  • 接收了一個 String
  • 發(fā)送了一個 String
  • 接收了一個 CustomType
    InitiatedBy flow 恰恰相反:
  • 接收了一個 Int
  • 發(fā)送了一個 String
  • 接收了一個 String
  • 發(fā)送了一個 CustomType
    只要 IntiatingFlowInitiatedBy flows 遵循這個有序的一系列的動作,那么 flows 就可以按照任何你覺得合適的方式來實現(xiàn)(包括添加不共享給其他節(jié)點的業(yè)務(wù)邏輯)。

哪些是非向下兼容的改動?

Flow 可以有兩種主要的方式會變?yōu)榉窍蛳录嫒莸模?/p>

  • sendreceive 調(diào)用的順序變化:
    1. 一個 send 或者 receiveInitiatingFlow 或者 InitiatedBy flow 中被添加或者刪除了
    2. sendreceive 調(diào)用的順序變了
  • sendreceive 調(diào)用的類型變了

當(dāng)運行不兼容版本的 flows 會發(fā)生什么?

帶有非兼容接口的 InitiatingFlowInitiatedBy flows 可能會出現(xiàn)下邊的行為:

  • flows 會沒有明確原因地停住了并且永遠也不會終止,通常是因為一個 flow 在等待這著一個回復(fù),但是這個回復(fù)永遠不會從另一方返回來
  • 其中的一個 flow 會帶有異常地結(jié)束:“Expected Type X but Received Type Y”,因為 send 或者 receive 類型不正確
  • 其中的一個 flow 會帶有異常地結(jié)束:“Counterparty flow terminated early on the other side”,因為一個 flow 向另外一個 flow 發(fā)送了一些數(shù)據(jù),但是后邊這個 flow 已經(jīng)結(jié)束了

我應(yīng)該如何升級我的 flows?

  1. 更新 flow 并且測試。在 InitiatingFlow 注解中增加 flow 版本號。
  2. 確保已經(jīng)存在的所有版本的 flow 已經(jīng)運行完了并且沒有未結(jié)束的 SchedulableFlows 在網(wǎng)絡(luò)中的任何節(jié)點中。這個可以通過清理節(jié)點的方式來實現(xiàn),接下來會講到。
  3. 關(guān)閉節(jié)點
  4. 用包含新的 flow 的 CorDapp JAR 文件替換掉原來的 CorDapp JAR
  5. 啟動節(jié)點

如果你關(guān)掉了所有的節(jié)點并且同時更新了他們的 flow 的話,可能產(chǎn)生任何的不兼容的改動。

對于一些節(jié)點可能仍舊繼續(xù)運行某個 flow 的以前版本的情況,這樣你的新版本 flow 可能會跟一個舊版本進行溝通,更新的 flows 需要具備向下兼容性。這可能是任何真正的部署中都會發(fā)生的問題,你可能不會很容易地去在整個網(wǎng)絡(luò)中去協(xié)調(diào)推出一個新的 code。

我該如何確保 flow 的向下兼容性?

InitiatingFlow 版本號會被包含在 flow session handshake 中并且通過 FlowLogic.getFlowContext 方法暴露給雙方。這個方法需要一個 Party 作為輸入,然后會返回一個 FlowContext 對象,這個對象描述了在對方節(jié)點上正在運行的 flow。它含有一個 flowVersion 的屬性,可以使用這個屬性來在不同的 flow 版本間來定制你自己的 flows,例如:

@Suspendable
override fun call() {
    val otherFlowVersion = otherSession.getCounterpartyFlowInfo().flowVersion
    val receivedString = if (otherFlowVersion == 1) {
        otherSession.receive<Int>().unwrap { it.toString() }
    } else {
        otherSession.receive<String>().unwrap { it }
    }
}

上邊的代碼演示了當(dāng) flow 的第一個版本期望收到一個 Int,但是后續(xù)的版本變成了期望收到一個 String。這個 flow 在跟其他仍然運行著包含舊的 flow 的舊的 CorDapp 之間還是能夠進行溝通的。

我該如何處理關(guān)于 in-lined subflows 的接口變化?

下邊是一個 in-lined subflow:

@StartableByRPC
@InitiatingFlow
class FlowA(val recipient: Party) : FlowLogic<Unit>() {
    @Suspendable
    override fun call() {
        subFlow(FlowB(recipient))
    }
}

@InitiatedBy(FlowA::class)
class FlowC(val otherSession: FlowSession) : FlowLogic() {
    // Omitted.
}

// Note: No annotations. This is used as an inlined subflow.
class FlowB(val recipient: Party) : FlowLogic<Unit>() {
    @Suspendable
    override fun call() {
        val message = "I'm an inlined subflow, so I inherit the @InitiatingFlow's session ID and type."
        initiateFlow(recipient).send(message)
    }
}

In-lined subflows 是當(dāng)跟對方初始一個新的 flow session 的時候被調(diào)用的 flows。假設(shè) flow A 調(diào)用 in-lined subFlow BB 初始了一個跟對方的會話(session)。對方使用的 FlowLogic 類型決定應(yīng)該調(diào)用哪個對應(yīng)的 flow 應(yīng)該是由 A 決定的,而不是 B。這意味著 in-lined flow 的 response logic 必須要在 InitiateBy flow 里被顯式地實現(xiàn)。這個可以通過調(diào)用一個匹配的 in-lined counter-flow,或者在對方的被初始的父的 flow 中顯式地實現(xiàn)。In-lined subflows 也會從他們的父 flow 中繼承 session IDs。

因此,一個 in-lined subflow 的一個借口的改動必須要考慮對父 flow 接口也要有一個改動。

一個 in-lined subflow 的例子是 CollectSignaturesFlow。他有一個沒有 InitiateBy 注解的 response 的 flow 叫 SignTransactionFlow。這是因為這兩個 flows 都是 in-lined。這兩個 flows 是如何彼此交流的是通過調(diào)用他們的父 flows 來定義的。

在代碼中,in-lined subflows 看起來就是一個常規(guī)的 FlowLogic 的實例,但是沒有 InitiatingFlow 或者 InitiatedBy 注解。

In-lined subflows 是沒有版本的,因為他們的版本是繼承于他們的父 flow 的(InitiatingFlowInitiatedBy)。

不是 InitiatingFlow 或者 InitiatedBy flow,也不是由一個 InitiatingFlow 或者 InitiatedBy flow 調(diào)用的 in-lined subflows ,更新的時候可以不考慮向下兼容的問題。這種類型的 flows 包括用來查詢 vault 的 utility flows,或者對外部系統(tǒng)進行查詢的 flows。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,695評論 19 139
  • feisky云計算、虛擬化與Linux技術(shù)筆記posts - 1014, comments - 298, trac...
    不排版閱讀 4,379評論 0 5
  • 我真正意義上完整看完的第一部韓劇,去年這個時候就看完了,直到今天偶然間又聽到了劇中的插曲,勾起了我全部的回憶...
    魚嚎閱讀 370評論 0 1
  • 如果有一天,可以選擇,我定會選擇遠走高飛,遠走他鄉(xiāng),我們不必活在別人的眼里,卻時時活在別人的眼中。 ...
    hello橙閱讀 637評論 0 1
  • 姜廣平老師不光光是一位優(yōu)秀的作家,還是一位優(yōu)秀的文學(xué)評論家。 說到文學(xué)評論,我還是在上大學(xué)的時候第一次聽說。當(dāng)時,...
    上官飛鴻閱讀 1,890評論 29 40

友情鏈接更多精彩內(nèi)容