考慮這樣一種情況:用orchestration處理一個order,在流程中做了處理後通過一個傳送埠傳送到商業夥伴那裡,然後需要明確的知道order確實通過傳送埠傳送到商業夥伴之後才能繼續之後的流程處理,如果傳送order沒有成功,則在orchestration中做異常處理。
按照biztalk的正常的訊息釋出訂閱機制,上述的情況是物理髮送埠訂閱orchestration的邏輯傳送埠傳送的order訊息,當orchestration把order訊息傳送到Messagebox,訊息引擎根據訂閱關係,把order訊息傳送到訂閱這個order的物理髮送埠,至此,orchestration傳送order的過程就算完成,至於物理髮送埠是否把訊息順利的傳送出去(可能順利的傳送了出去,可能在傳送埠內部出錯,也可能從埠傳送出去後從另一端返回錯誤資訊)orchestration無從知道。
針對這種情況,biztalk提供一種反饋機制,傳送埠(單向傳送埠或者雙向傳送埠)可以根據需要返回傳送成功的ACK訊息(Positive Acknowledgment)和傳送失敗的NACK訊息(Negative Acknowledgment),如果傳送埠成功的把訊息傳送出去了,則可以返回ACK訊息,如果傳送埠傳送訊息失敗(不管是傳送埠內部出錯還是傳送出去後收到錯誤資訊),則返回NACk訊息。Orchestration收到ACK或者NACK訊息後,就可以知道訊息是否正常的傳送出去了,根據得到的反饋訊息,進行之後的流程。一般的收到ACK反饋訊息,流程正常的繼續下去,收到NACK訊息,orchestration會生成一個DeliveryFailureException異常,在orchestration中可以設計一個異常捕獲,捕獲DeliveryFailureException異常後進行異常處理。
深入分析反饋機制
要使用傳送埠反饋機制,需要做一些設定。
l 邏輯傳送埠的Delivery Notification屬性設定為 Transmitted
這是告訴biztalk訊息引擎,傳送出去的訊息是需要反饋訊息的。
l Send shap所在scope的Synchronizd屬性設定為true
(但是測試表明,這個屬性跟ACK或NACK的反饋關係不大)
l Scope形狀可以設定Exception Handler捕獲DeliveryFailureException異常
如果從物理髮送埠返回的NACK訊息,那麼orchestration將在這個scope的位置產生一個DeliveryFailureException異常,可以被Scope形狀的Exception Handler捕獲,進而進行進一步的異常處理。
下面詳細分析一個訊息在orchestration被髮送出去後,到orchestration收到ACK訊息或者NACK訊息的整個過程的底層機制。
一、 orchestration中訊息從邏輯埠發出
訊息在orchestration到達邏輯傳送埠時,因為邏輯傳送埠的Delivery Notification屬性設定為 Transmitted,biztalk將會做兩件事:
1、 在訊息的上下文屬性中增加一個系統屬性:AckRequired = true
在將要傳送出去的訊息的上下文屬性中,增加一個系統屬性AckRequired = true,這個屬性的作用是告訴接收這個訊息的物理髮送埠,此訊息是需要反饋訊息的,物理髮送埠在收到的訊息中發現有這個屬性,就會在埠傳送訊息成功後形成ACK訊息,在傳送失敗後生成NACK訊息,併發布訊息。
如果邏輯傳送埠的Delivery Notification屬性設定為none,訊息中將不會包含AckRequired = true的系統屬性,物理髮送埠也不會生成ACK或NACK訊息併發布。
2、 在邏輯傳送埠位置新建一個例項訂閱,訂閱傳送埠返回的ACK或NACK訊息。
首先在邏輯傳送埠處初始化一個correlation token(相關標識)賦給出站訊息的上下文的系統屬性CorrelationToken。
之後新建一個例項訂閱,訂閱者為這個orchestration服務例項的邏輯傳送埠。看一下資料庫Subscription訂閱表中的一個此類例項訂閱的一個示例:
uidSubID(此例項訂閱的uid) -- 2b78f65c-a983-4a49-b626-afc551d54c98
uidClassID(產生訂閱的服務型別) -- 226fc6b9-0416-47a4-a8e8-4721f1db1a1b(表示是XLANG/s服務)
uidServiceID(產生此訂閱的具體服務)-- 63eb391b-37ee-3243-56b1-e93e8bd7ec05(這個orchestration的guid)
uidPortID(表示業務流程中訂閱訊息的埠shape)-- 63eb391b-37ee-3243-5622-7452edd13162(傳送訊息的邏輯埠,ACK或NACK還是由它來接收)
uidInstanceID(產生此訂閱的例項的guid)-- ba1eff99-c1b2-447b-882d-d391e1b17b6f(此orchestration服務例項的guid)
這個例項訂閱的條件在messagebox資料庫中的EqualsPredicates表中,看一下這個例項訂閱的訂閱條件示例,條件就一個,訊息的系統屬性CorrelationToken為相關集的token:
uidPropID(屬性guid)-- 593badb0-43fb-40c2-a211-8e148f102109(查閱bt_DocumentSpec系統屬性表,這個guid表示的系統屬性為http://schemas.microsoft.com/BizTalk/2003/system-properties#CorrelationToken,即系統屬性CorrelationToken)
vtValue(屬性的值) -- 31e04a93-9e4a-4584-8c7b-71e09c733ed3(就是初始化的那個相關集的token)
在給出站訊息新增了系統屬性AckRequired和CorrelationToken後,orchestration把訊息釋出到messagebox,同時生成一個例項訂閱,訂閱系統屬性CorrelationToken相符的訊息。在訊息釋出出去後,直到直接外層long running scope結束處,等待ACK或者NACK訊息的返回。
二、 訊息在傳送埠
物理髮送埠訂閱了orchestration邏輯傳送埠的訊息,在收到訊息後,物理髮送埠發現有AckRequired和CorrelationToken屬性,知道這個訊息是需要提供反饋的。
物理埠執行正常的傳送工作,將收到的訊息經過傳送管道,傳送介面卡傳送出去。
如果訊息成功的傳送了出去,物理髮送埠就會生成一個ACK訊息,這個ACK訊息只有上下文屬性,沒有訊息正文,ACK包含的屬性有:
屬性名
|
描述
|
BTS.AckFailureCategory |
Identifies the ErrorCategory, which gives the place and reason for the suspension. |
BTS.AckFailureCode |
Identifies the ErrorCode, which gives the place and reason for the suspension. |
BTS.AckType |
Value is ACK for a positive acknowledgment and NACK for a negative acknowledgment. |
BTS.AckID |
Identifies the MessageID of the original message. |
BTS.AckOwnerID |
Identifies the instance ID from the original message. |
BTS.CorrelationToken |
Identifies the correlation token from the original message if one is present. |
BTS.AckDescription |
Identifies the ErrorDescription, which gives the place and reason for the suspension. |
BTS.AckSendPortID |
Identifies the SendPortID from the original message. |
BTS.AckSendPortName |
Identifies the SendPortName from the original message. |
BTS.AckOutboundTransportLocation |
Identifies the OutboundTransportLocation from the original message. |
BTS.AckReceivePortID |
Identifies the ReceivePortID from the original message. |
BTS.AckReceivePortName |
Identifies the ReceivePortName from the original message. |
BTS.AckInboundTransportLocation |
Identifies the InboundTransportLocation from the original message. |
其中的CorrelationToken屬性就是傳送埠從接收到訊息上下文屬性中這個屬性獲取的。傳送埠釋出這個ACK訊息後,orchestration要靠匹配這個屬性獲得ACK訊息。
如果訊息傳送失敗,包括訊息在物理髮送埠內部出錯,訊息傳送出了物理髮送埠後從對方收到了錯誤資訊,傳送埠都會生成一個NACK訊息。NACK訊息跟ACK訊息一樣擁有上述的上下文屬性,另外NACK還有一個SOAP fault的訊息正文,一般形式如下:
<?xml version="1.0" encoding="utf-8"?> <SOAP:Envelope xmlns:SOAP="http://schemas.xmlsoap.org/soap/envelope/" SOAP:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <SOAP:Body> <SOAP:Fault> <faultcode>Microsoft BizTalk Server Negative Acknowledgment </faultcode> <faultstring>An error occurred while processing the message, refer to the details section for more information </faultstring> <faultactor>C:\Projects\Sample\Locations\Response\FM_%MessageID%.xml</faultactor> <detail> <ns0:NACK Type="NACK" xmlns:ns0="http://schema.microsoft.com/BizTalk/2003/NACKMessage.xsd"> <NAckID>{FFB1A60B-E593-4620-8897-4E9C7030A937}</NAckID> <ErrorCode>0xc0c01658</ErrorCode> <ErrorCategory>0</ErrorCategory> <ErrorDescription>There was a failure executing the send pipeline: "Microsoft.BizTalk.DefaultPipelines.XMLTransmit, Microsoft.BizTalk.DefaultPipelines, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" Source: "XML assembler" SendPort: "Failed Message" URI: "C:\Projects\Sample\Locations\Response\FM_%MessageID%.xml" Reason: This Assembler cannot retrieve a document specification using this type: "http://Sample#Unknown". </ErrorDescription> </ns0:NACK> </detail> </SOAP:Fault> </SOAP:Body> </SOAP:Envelope> |
物理髮送埠在傳送訊息失敗後,把傳送埠服務例項掛起,同時釋出NACK訊息。
三、 ACK或NACK返回orchestration
傳送埠釋出ACK或NACK訊息後,根據例項訂閱的訂閱條件(CorrelationToken),訊息引擎把ACK或NACK訊息路由到傳送訊息的那個orchestration服務例項。
如果接收到的是ACK訊息,orchestration從之前停留等待反饋訊息的傳送形狀那裡繼續按照正常的流程繼續下去。
如果接收到的是NACK訊息,orchestration在傳送形狀所在的scope產生一個DeliveryFailureException異常,異常可以被scope的exception handler捕獲,在異常處理中做相應的處理。
在異常處理中可以:
// 把DeliveryFailureException型別轉換成 SoapException型別
System.Web.Services.Protocols.SoapException se = (System.Web.Services.Protocols.SoapException)e.InnerException;
System.Diagnostics. EventLog.WriteEntry (“NACK內容”,se.Detail.InnerXml);
下面就是可以在windows日誌中看到返回的NACK詳細內容的xml:
<ns0:NACK Type="NACK" xmlns:ns0="http://schema.microsoft.com/BizTalk/2003/NACKMessage.xsd">
<NAckID>{BD6682EE-1741-4856-8CC7-B2EE36B7874E}</NAckID>
<ErrorCode>0xc0c01c10</ErrorCode>
<ErrorCategory>0</ErrorCategory>
<ErrorDescription>The FILE send adapter cannot open file C:\Foo\DeliveryNotification\out\{505A3211-9081-4720-827B-A0DE2BD124FD}.xml for writing. </ErrorDescription>
</ns0:NACK>
以上過程就是一個設定了Delivery Notification屬性的傳送埠傳送訊息的整個過程。
此外,ACK或NACK訊息處理除可以被髮送訊息的orchestration本身接收外,還可以設計一個專門的orchestration,根據NACK訊息的系統屬性,通過Content-based的路由NACK訊息,接收biztalk應用中所有的NACK訊息,然後進行相關的處理,比如統一記入錯誤日誌,做錯誤統計等等。
參考:
biztalk文件Development > Developing BizTalk Server Applications > Using the BizTalk Messaging Engine > Error Handling > Using Acknowledgments
Kevin B Smith 《Acknowledgments and Negative Acknowledgments (Part 1)》