批次處理接收訊息
批次回呼
由接收配接器提交至傳訊引擎的批次是以非同步方式處理。 因此,配接器需要某種機制,將回呼繫結至配接器中的某個狀態,這樣才能夠收到成功或失敗的通知,並執行任何必要的清理動作。 回呼語意相當有彈性,因此配接器可以使用三個方法中的其中一種或任意組合。 這些工具為:
所有回呼都會建立在實作 IBTBatchCallBack的相同物件實例上。
使用要求新批次時傳遞到引擎中的 Cookie,使回呼與配接器中的狀態產生相互關聯。
每個實作 IBTBatchCallBack的批次都有不同的回呼物件。 這裡的每個物件都具有本身的私用狀態。
處理批次之後,會在其 IBTBatchCallBack.BatchComplete 的實作上呼叫配接器。 批次的整體狀態由第一個參數 HRESULT 狀態顯示出來。 如果這個值大於或等於零,即表示批次已成功,因為引擎具有資料的擁有權,而配接器可以自由地從連線上刪除該項資料。 負數的狀態表示批次失敗:批次中沒有任何作業成功,而配接器將負責處理失敗。
如果批次失敗,配接器就必須知道是哪一項作業的哪一個項目失敗。 例如,假設配接器從磁片讀取 20 個檔案,並使用單一批次將它們提交至BizTalk Server。 如果第十個檔案損毀,配接器必須暫停該檔案,然後重新提交其餘的 19 個檔案。 此資訊適用于第二和第三個參數中的配接器,
opCount
(短型別和operationStatus
類型的作業計數) ,其類型為 BTBatchOperationStatus[]。
注意
對於單一批次物件,您絕對不要提交訊息一次以上。 在同一批次上多次提交相同訊息物件會導致引擎錯誤。
作業計數會指出批次中有多少類型的作業 (BTBatchOperationStatus 陣列的大小) 。 作業狀態陣列中的每個元素會對應至指定的作業類型。 藉由使用 BTBatchOperationStatus 陣列,配接器可以查看 BTBatchOperationStatus.MessageStatus 陣列來判斷指定作業中的哪個專案失敗,以取得負數 HRESULT 值。 在上面的實例中,配接器會建立一個新批次,其中包含 19 個訊息提交和 1 個訊息擱置。
下列程式碼片段顯示配接器如何透過傳輸 Proxy 向引擎要求新批次,並使用 Cookie 的方式提交單一訊息到引擎中。 傳訊引擎會在完成處理整個提交的訊息批次時,呼叫 BatchComplete 方法做為批次回呼。
using Microsoft.BizTalk.TransportProxy.Interop;
using Microsoft.BizTalk.Message.Interop;
public class MyAdapter :
IBTTransport,
IBTTransportConfig,
IBTTransportControl,
IPersistPropertyBag,
IBaseComponent,
IBTBatchCallBack
{
private IBTTransportProxy _tp;
public void BatchComplete(
Int32 status,
Int16 opCount,
BTBatchOperationStatus[] operationStatus,
System.Object callbackCookie)
{
// Use cookie to correlate callback with work done,
// in this example the batch is to submit a single
// file the name of which will be in the
// callbackCookie
string fileName = (string)callbackCookie;
if ( status >= 0 )
// DeleteFile from disc
File.Delete(fileName);
else
// Rename file to fileName.bad
File.Move(fileName, fileName + ".bad");
}
private void SubmitMessage(
IBaseMessage msg,
string fileName)
{
// Note: Pass in the filename as the cookie
IBTTransportBatch batch =
_tp.GetBatch(this, (object)fileName);
// Add msg to batch for submitting
batch.SubmitMessage(msg);
// Process this batch
batch.Done(null);
}
}
BizTalk Server SDK 包含下列配接器的範例:檔案、HTTP、MSMQ 和交易式配接器。 這些配接器全都是建立一個通用建置組塊上,稱為 BaseAdapter。 BaseAdapter 的 1.0.1 版包含所有相關的程式碼,可用來剖析作業狀態和重建新批次以進行提交。
競爭情形
解決錯誤以及決定提交批次最後結果的這兩項工作,似乎相當簡單,但事實上它們需要依賴來自不同執行緒的資訊:
配接器會根據BizTalk Server傳遞至配接器的BatchComplete回呼方法所傳遞的資訊來處理錯誤。 這個回呼會在配接器的執行緒上執行。
DTCCommitConfirm 是 IBTDTCCommitConfirm 物件上的方法。 IBTDTCCommitConfirm物件的實例是由批次IBTTransportBatch::D one呼叫所傳回。 這個實例位於與 IBTTransportBatch::D one 呼叫相同的執行緒上,這與配接器的回呼執行緒不同。
針對介面卡對 IBTTransportBatch::D傳 訊引擎對個別執行緒中的回呼方法 BatchComplete 進行對應的呼叫,以報告批次提交的結果。 在 BatchComplete 中,介面卡必須根據批次通過或失敗來認可或回復交易。 不論是哪一種情況,配接器都應該呼叫 DTCCommitConfirm 來報告交易的狀態。
可能競爭條件存在,因為配接器的BatchComplete實作可以假設IBTDTCCommitConfirm物件在BatchComplete執行時一律可以使用IBTTransportBatch::D one。 不過, BatchComplete 可以在個別的傳訊引擎執行緒中呼叫,即使在 IBTTransportBatch::D one 傳 回之前也是如此。 當配接器嘗試存取 IBTDTCCommitConfirm 物件作為 BatchComplete 實 作的一部分時,可能會發生存取違規,因為該呼叫執行緒已不存在。 請使用下列解決方法來避免這個情形。
在下列範例中,將使用事件來解決問題。 這裡會使用事件的屬性來存取介面指標。 Get 方法永遠會等到 Set 方法完成後才繼續。
protected IBTDTCCommitConfirm CommitConfirm
{
set
{
this.commitConfirm = value;
this.commitConfirmEvent.Set();
}
get
{
this.commitConfirmEvent.WaitOne();
return this.commitConfirm;
}
}
protected IBTDTCCommitConfirm commitConfirm = null;
private ManualResetEvent commitConfirmEvent = new ManualResetEvent(false);
批次狀態碼
整體批次狀態碼會指出批次處理的結果。 作業狀態會提供提交狀態碼給個別訊息項目。 批次失敗的原因有很多種。 可能是發生有關安全性的失敗,或是當提交訊息時,引擎正在關閉 (通常當引擎關閉時,它不接受任何新工作,但允許完成同進程工作。) 下表指出批次狀態或作業狀態中傳回的一些常見 HRESULT 值。 同時也會指出這些值是成功碼,還是失敗碼。 如何處理配接器 失敗中會更完整地說明這些程式碼的適當處理方式。
代碼 (在類別 BTTransportProxy 中定義) | 成功/失敗碼 | Description |
---|---|---|
BTS_S_EPM_SECURITY_CHECK_FAILED | Success | 連接埠已設定為執行安全性檢查,並捨棄驗證失敗的訊息。 配接器不會擱置傳回這個狀態碼的批次。 |
BTS_S_EPM_MESSAGE_SUSPENDED | Success | 表示有一則或多則訊息被擱置,而引擎具有資料的擁有權。 這是成功碼,因為傳訊引擎已經接受訊息提交。 |
E_BTS_URL_DISALLOWED | 失敗 | 已提交無效 的 InboundTransportLocation訊息。 |
批次作業
下表詳細說明配接器用來將工作新增至指定批次之 IBTTransportBatch 物件的成員方法和作業。
方法名稱 | 作業類型 | 描述 |
---|---|---|
SubmitMessage | 送出 | 將訊息提交到引擎中。 |
SubmitResponseMessage | 送出 | 將回應訊息提交到引擎中。 這是成對的「請求-回應」中的回應訊息。 |
DeleteMessage | 刪除 | 刪除因為配接器使用非封鎖傳送方式透過連線成功傳輸而產生的訊息。 使用封鎖傳送的配接器不需要呼叫此方法,因為如果配接器從TransmitMesssage傳回 true 配接器,傳訊引擎會代表配接器將其刪除。 |
MoveToSuspendQ | MoveToSuspendQ | 將訊息移到訊息擱置佇列中。 |
提交 | Resubmit | 要求稍後重新嘗試傳送訊息。 這通常會在傳輸嘗試失敗之後被呼叫。 |
MoveToNextTransport | MoveToNextTransport | 要求使用其備份傳輸來傳送訊息。 這通常會在用盡所有嘗試次數而仍失敗之後被呼叫。 如果沒有備份傳輸,這個方法將會失敗 |
SubmitRequestMessage | SubmitRequest | 提交要求訊息。 這是成對的「要求-回應」中的要求訊息。 |
CancelRequestForResponse | CancelRequestForResponse | 通知引擎:配接器已經不再等待成對的「要求-回應」中的回應訊息。 |
清除 | NA | 從批次清除所有工作。 |
完成 | NA | 將訊息批次提交給引擎進行處理。 |
Batch 管理
批次是在傳訊引擎中以原生程式碼來實作的。 因此,以 Managed 程式碼撰寫的配接器應該在完成批次後,為批次發佈執行階段可呼叫包裝函式 (RCW)。 這是使用 Marshal.ReleaseComObject API 在 Managed 程式碼中完成的。 請務必記得要在 while 迴圈中呼叫這個 API,直到傳回的參考計數到達零為止。
BizTalk Server在批次內同步處理訊息。 您可以並行處理許多批次,如此可以藉由調整應用程式定義域中的批次大小,在配接器中進行一些最佳化工作。 例如,您可以處理 FTP 網站上的所有檔案 (直到達到某個限制為止)。 在 SAP 的情況下,您可以將單一資料流處理成一些接下來會以批次方式提交的訊息。
配接器用來將作業傳回給BizTalk Server的批次不需要完全符合BizTalk Server提供給配接器的訊息清單。 換句話說,執行交易式傳送時,您必須將重新提交作業 MoveToNextTransport 和 MoveToSuspendQ 分割成個別的批次。 許多配接器會將已經提交給多個結束點的訊息批次區分為不同的訊息清單,以作進一步處理。
點在於,除了與BizTalk Server中訊息批次處理相關聯的交易) 相關聯的交易之外,沒有任何規則 (。 批次處理只是配接器在BizTalk Server中區塊訊息的實作特定方式。
配接器可以從多個較小的批次批次處理訊息,BizTalk Server已將其提供給較大的批次,以便回應BizTalk Server。 這在處理大量小型訊息的交易式配接器中,可能是一項重大的最佳化成果。 它會將「每則訊息的交易總數」比率降至最低。
通常BizTalk Server會產生介於 5 到 10 個訊息之間的傳送端批次。 如果這些是非常小型的訊息,配接器可能會在將交易式刪除批次提交回BizTalk Server之前,最多批次處理 100 個訊息或更多訊息。 像這樣的最佳化並不容易實作;您必須確定訊息不會滯留於配接器記憶體中,無止境地等待達到某個閾值。
在 MQSeries 等高輸送量配接器的BizTalk Server效能數位中,可以看到批次處理的重要性。 這些配接器是以至少為傳送頻率兩倍的頻率來接收訊息。 根據預設,接收配接器會使用 100 個訊息的批次,而傳送配接器會使用它所提供的預設BizTalk Server批次。
交易批次
當您撰寫建立交易對象的配接器,並將它交給BizTalk Server時,您必須負責撰寫執行下列動作的程式碼:
決定批次作業的最後結果:認可或結束交易。 這可能相依于此交易範圍中的其他交易分支,這些交易不BizTalk Server相依,例如寫入訊息佇列 (MSMQ) 佇列或交易資料庫作業。
藉由呼叫IBTDTCCommitConfirm.DTCCommitConfirm方法,通知BizTalk Server最終結果。 傳
true
回表示交易成功認可;傳false
回表示失敗和交易回復。配接器必須通知BizTalk Server交易的最終結果,以維護其內部追蹤資料。 配接器會呼叫DTCCommitConfirm來通知BizTalk Server結果。 如果配接器不這麼做,就會發生嚴重的記憶體遺漏,而且即使作業成功完成,MSDTC 交易還是會逾時並失敗。