一般而言,配接器應該暫停無法處理的訊息。 例如,遇到送出失敗的接收配接器通常應該暫停訊息,不過此決策取決於配接器的目的。 在處理故障的過程中,也需要考慮安全問題。 例如,如果配接器自動暫停所有失敗的訊息,配接器可能會受到拒絕服務攻擊,這導致 BizTalk Server 的暫停佇列填滿。 某些配接器,例如 HTTP,可以將錯誤碼傳回給用戶端,指出請求已被拒絕。 對於這些類型的配接器,傳回失敗碼而不是暫停訊息通常很合理。 一般而言,傳送配接器只會在主要和次要傳輸用盡所有重試之後暫停訊息。
將錯誤處理與個別作業產生關聯,而不是與包含作業的批次產生關聯
配接器內的訊息批處理應該對配接器的使用者看不見。 這表示批次中某個作業的失敗不應以任何方式影響任何其他作業。 不過,批次具有整體性,因此一則訊息的失敗會導致整個批次失敗,任何作業都不會被處理。
您可以撰寫負責處理錯誤的程式代碼、重新提交成功的訊息,以及暫停失敗的訊息。 幸運的是,BizTalk Server 提供詳細的錯誤結構,可讓您的配接器判斷失敗的特定作業。 它允許進行進一步的批次作業,其中成功的作業將被重新提交,而失敗的作業則暫停。
作業的最終狀態不應受到配接器內的批處理影響。
使用 "SetErrorInfo" 向 BizTalk Server 報告失敗
如果您要暫停訊息,您必須從先前的訊息內容將失敗資訊提供給 BizTalk Server。 BizTalk Server 在 IBaseMessage 和 ITransportProxy 介面上使用 SetErrorInfo 方法提供錯誤報告功能。 您可以回報錯誤,如下所示:
處理訊息時發生失敗時,請在訊息上使用 SetErrorInfo(Exception e) 設定例外狀況,以暫停訊息 (IBaseMessage)。 這可讓引擎保留錯誤訊息以供稍後診斷,並將它記錄至事件記錄檔,以警示系統管理員。
如果您在初始化或內部記賬期間遇到錯誤(而不是在訊息處理期間),您應該在初始化期間傳遞給您的 ITransportProxy 指標上呼叫 SetErrorInfo(Exception e)。 如果您的適配器是以 BaseAdapter 實作為基礎,您應該總是可以存取此指標。 否則,您應該確認快取它。
使用其中一種方法回報錯誤,會導致錯誤訊息寫入事件記錄檔。 如果您能夠這麼做,請務必將錯誤與相關的訊息產生關聯。
處理 Database-Offline 條件
如果其中一個 BizTalk Server 資料庫脫機,BizTalk 服務就會自行回收。 傳訊引擎會盡最大努力關閉所有接收位置,再重啟服務。 如果這需要超過 60 秒的時間,服務就會終止。 因為引擎已交易,這不會造成數據遺失。
這個逾時可以在登錄中使用金鑰進行調整:
DWORD
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\BTSSvc{Host Guid}\MessagingDBFailoverShutdownTimeLimit
若為獨立的配接器,由於 BizTalk Server 不控制該程序,因此當其中一個 BizTalk Server 資料庫離線時,就會停用接收端點。 資料庫重新上線之後,這些接收位置會重新啟用。
寫入事件記錄檔
配接器可以使用 IBTTransportProxy 介面來傳遞例外狀況,從而寫入事件記錄。 原生程式碼開發的配接器需要傳入IErrorInfo介面,IBTTransportProxy.SetErrorInfo(Exceptione
)。
傳訊引擎會代表適配卡寫入事件記錄檔,例如適配卡在傳輸失敗後重試訊息、將訊息移至其備份傳輸,或暫停訊息。 針對這類作業,配接器只需要在呼叫 API 之前,在訊息上設定例外狀況。 下列程式碼片段示範此操作:
IBaseMessage msg;
...
// Set exception on msg to indicate why transmission failed...
msg.SetErrorInfo(
new ApplicationException(
"The TCP connection was closed by the destination"));
處理 Receive-Specific 批次錯誤
處理接收失敗
當配接器將作業(或作業批次)提交至 BizTalk Server 時,可能會有各種失敗原因。 最重要的兩個是:
接收管線失敗。
發佈訊息時發生路由失敗。
傳訊引擎會在收到管線失敗時自動嘗試暫停訊息。 暫停作業不一定會成功。 例如,如果訊息引擎在發佈訊息時遇到路由失敗,則引擎甚至不會嘗試暫停訊息。
訊息總是有可能失敗。 在這種情況下,配接器應該明確地呼叫 MoveToSuspendQ API,並且應該嘗試暫停訊息。 當配接器嘗試暫停訊息時,下列其中一項應該是正確的:
應該暫停配接器送出 (建議) 的相同訊息物件。
如果配接器必須建立新的訊息,則它應該將新訊息的訊息內容設定為原始送出訊息的訊息內容指標。 這是因為訊息的訊息內容有許多關於訊息和失敗的寶貴資訊。 需要此資訊才能偵錯失敗的訊息。
備註
如果配接器建立新的訊息物件並暫停它,配接器應該將錯誤資訊從舊的訊息物件複製到新的訊息物件。
某些配接器,例如 BizTalk Server 提供的 HTTP 配接器,不需要暫停訊息。 這些配接器可以將錯誤傳回其用戶端。
失敗的原因
簡單的失敗原因是建構批次或呼叫 IBTTransportBatch::Done 時可能發生的錯誤。
提交失敗。 送出通話可能會因為少數原因而失敗,而且全部都是致命的。 這些原因包括:
BizTalk Server 進程空間中發生的記憶體不足錯誤。
模式組件已從部署中移除。 在此情況下, 送出 會失敗,並出現神秘錯誤。 在 MQSeries 配接器中,擷取 BizTalk Server 的一般故障例外狀況,將擴充錯誤訊息寫入系統事件日誌中。 此訊息建議錯誤的其中一個可能原因是結構組件因某種原因被移除出部署。
一般而言,如果 Submit 失敗,您應該嘗試使用相同的交易暫停訊息。
IBTTransportBatch::Done 失敗。 IBTTransportBatch::Done 呼叫可能因為某些原因而失敗。 一般而言,您應該一律嘗試進行一次暫停作業,僅在該作業失敗時才終止交易。 您可能在 IBTTransportBatch::Done 失敗時收到的錯誤碼之一是 BizTalk Server 正在嘗試關閉。 在此情況下,您應該只結束交易並暫時不予理會,因為可能有 Terminate 呼叫同時發生。 當您成功建構批次並成功執行 IBTTransportBatch::Done 時,可能會出現其他情況。 在這些情況下,BatchComplete 中會傳回錯誤,而且配接器必須判斷如何處理它們。 本節的其餘部分會處理此案例。
處理「BatchComplete」錯誤
BatchComplete 是由 BizTalk Server 叫用的配接器提供的回呼,指出批次作業的完成狀態。
傳遞至 BatchComplete 的最重要參數是批次狀態 hResult
。 這表示批次的成功或失敗。 如果批次失敗,表示批次中沒有任何作業成功。 配接器會經歷批次狀態結構,並判斷哪些訊息失敗(這稱為 篩選批次)。
非交易批次完成錯誤
針對非交易型配接器,當 SubmitMessage、SubmitRequestMessage 或 SubmitResponseMessage 作業發生失敗時,您必須選擇您的回應。 通常會藉由呼叫 MoveToSuspendQ來暫停訊息。
預期下列操作將順利完成:DeleteMessage、MoveToSuspendQ、ResubmitMessage。 如果這些作業失敗,通常表示適配卡中有錯誤。 在這些情況下,您不需要撰寫程式代碼來處理失敗。 不過,如果批次因為另一個作業失敗而失敗,則必須在新的批次中重新執行這些作業。
如果配接器呼叫 MovetoBackupTransport 且失敗(因為沒有備份傳輸),則配接器應該呼叫 MoveToSuspendQ 來暫停訊息。
交易性 BatchComplete 錯誤
當您使用配接器所建立的交易將批次提交至 BizTalk Server 時,您應該遵循下列兩個案例之一:
使用單一訊息批次。 將單一訊息批次傳送至 BizTalk Server。 如果該單一訊息失敗,您可以合法地在同一筆交易下傳送 BizTalk Server 第二個批次,但您必須將違規訊息移至暫停的佇列,而不是重新提交它。 拿掉失敗的訊息之後,第二批的提交應該會成功。 在那之後,您可以在 BizTalk Server 確認第二個批次成功時提交交易。 如果第二個批次失敗,配接器必須中止交易,或尋找其他地方來放置該訊息。 在此情境下,由於交易回滾處理,您會立即遭受顯著的效能損失。
有一些技術可用來改善配接器的效能。 例如,MQSeries 配接器會在運行時間動態調整其方法。 它以一批 100 條訊息的方式運行。 如果它遇到錯誤,必須結束該批次,但會暫時切換為單一訊息批次,以便跳過不正確的訊息。 然後,它會還原成100個訊息批次。 如果再次遇到錯誤,則會再次變慢速度。
使用預防性暫停。 建立多重訊息批次,其中的錯誤訊息會被預先暫停。 批次包含 Submit 和 MoveToSuspendQ 作業的混合,而且是交易下第一個且唯一的批次。 它應該會成功,因為不正確的數據已預先中止,交易可以提交(在等候從 BizTalk Server 收到確認之後)。
這似乎需要研究未來,但已在 MSMQ 配接器中使用這項技術。 這取決於有可靠的唯一訊息標識碼。 此配接器會生成一組訊息。 如果有任何失敗,它會回復交易(因此為批次),但會記住暫存數據結構中的訊息標識碼。 (為了避免這種結構無限地成長,在固定時間延遲後會移除其中的項目。)提交每個批次之前,配接器會檢查不正確的訊息 ID 清單。 如果看到訊息,它知道訊息會失敗(因為它過去失敗一次),並預先暫停它,而不是嘗試提交它。
並非每個配接器都有可靠的唯一訊息標識符,而且交易存放區不太可能有一個。 因此,許多交易式配接器僅限於傳送單一訊息批次。
處理其他錯誤
在其他所有情況下(例如暫停訊息失敗),配接器必須結束交易。 任何其他結果都會導致重複或遺失的訊息。
每當配接器可以時,如果批次失敗,就應該中止交易。 不過,在某些情況下,配接器無法中止交易。 在這種情況下,它應該使用相同的交易來暫停訊息。
在事務性接收中的處理錯誤
常見的交易處理模式是在發生錯誤時結束交易。 在此情況下,所有專案都傳回其先前的狀態,且不會遺失任何數據。 不過,如果您要從交易數據流中取用資料(例如,從資料庫的中介表中一次提取一行資料,或一次從像是 MQSeries 或 MSMQ 的佇列系統中提取一則訊息),那麼這可能不夠。 如果您只是結束交易,並再次返回並挑選相同的數據,可能會發生相同的錯誤,而且系統會卡在重複迴圈中。
舊版 BizTalk Server 中的 SQL 配接器具有此行為。 不過,發行之後不久,配接器行為會變更為嘗試暫停失敗的訊息並認可交易。 將訊息移至相同交易下的 [暫存] 佇列後提交交易,可以儲存資料避免遺失,並允許配接器跳過不良的數據。
當配接器的接收部分傳遞錯誤訊息以回應 送 出訊息作業時,配接器應該處理該錯誤,並將訊息移至暫停的佇列。
如果交易批次中配接器已建立交易物件,並在交易下提交訊息,配接器應該在發生失敗時,以邏輯方式將訊息移至相同交易下的暫停佇列。 交易可確保不會卸除數據,甚至造成錯誤的數據也不應該卸除。
處理無需訂閱的訊息
如果沒有定義接受訊息的訂用帳戶,BizTalk Server 就不會接受要在其 MessageBox 資料庫中發佈的訊息。 訂閱是由協調程序或傳送埠設定。 您可以定義多個訂用帳戶,在此情況下,訊息會傳送至多個目的地。 如果沒有訂用帳戶,BizTalk Server 會拒絕訊息,而且不會嘗試暫停訊息。 如果配接器未處理此錯誤並明確暫停訊息,則會卸載訊息,而且可能會遺失其數據。 當然,交易式配接器可能會結束交易,並將訊息傳回至其目的地。
使用接收數據流尋求支援
接收端數據流必須支援 BizTalk Server 的 Seek 方法,才能在管線失敗時暫停訊息。 如果無法搜尋訊息數據流,則 BizTalk Server 會在嘗試執行 Seek 時產生錯誤。
在許多情況下,支援 Seek 並不容易。 例如,從網路串流數據時,可能很難回到網路資源,並再次要求數據。
與 BizTalk Server 一同附帶的數個配接器會將訊息數據暫存到磁碟上的檔案,與此同時,BizTalk Server 會讀取數據。 這可讓適配器在處理該檔案時,若遇到錯誤(例如,在訊息數據的管線處理中),使用 Seek。 在內部,配接器會使用 ReadOnlySeekableStream 類別,在達到可設定的大小臨界值時包裝傳入的不可搜尋數據流並溢位至磁碟。 對於小於臨界值大小的訊息,磁碟永遠不會被存取。
請考慮選項 User-Configurable Error-Handling
有時候,對錯誤沒有唯一正確的回應。 在此情況下,您應該考慮用戶可設定的選項,以在行為之間進行選擇。 MQSeries 配接器會執行此作業。
當配接器偵測到錯誤而暫停訊息時,問題在於 BizTalk Server 中的暫停佇列有如「黑洞」。將訊息送入佇列相對容易,但要再次取出則較為困難。
適配器的某些使用者可能不希望暫停佇列中有任何項目。 例如,在 MQSeries 配接器的情況下,使用者會提供組態選項來執行下列其中一項動作:
當發現錯誤時,將配接器設定為結束目前的交易並自我停用。
暫停失敗的訊息並認可交易。 即使 BizTalk Server 已成功暫停訊息,配接器也會執行此作業。 此動作符合客戶的需求,即使它導致事件記錄檔不正確也一樣。
使用單一執行緒並等待 BatchComplete 來實現接收排序
BizTalk Server 的介面是針對效能和支援並行擴增的能力所設計。 不過,如果您想要嚴格排序地接收訊息(比如在從 MQSeries 或 MSMQ 等訊息佇列產品接收訊息時,有時會需要這樣做),則必須在配接器中進行一些額外的工作以停用部分並行處理。 這可以在兩個步驟中完成:
您必須針對配接器中的所有數據處理使用單一線程。
您必須等候 BizTalk Server 完整處理每個批次。 這項需求很重要,而且可以使用 .NET 線程同步處理基本類型來完成。 例如,使用 AutoResetEvent,您可以:
宣告事件物件,使其可由主要工作執行緒和 BatchComplete 回呼物件存取。
在主要工作線程上,如往常一樣將訊息提交至批次,但在呼叫批次 IBTTransportBatch::Done 之前,於事件物件上呼叫 AutoResetEvent.Reset。
從這個相同線程的事件對象上呼叫 AutoResetEvent.WaitOne 。 這會導致主要工作線程被封鎖。 在 BizTalk Server 的 BatchComplete 回呼中,您接著在同一個事件物件上呼叫 AutoResetEvent.Set ,以解除封鎖背景工作線程,使其準備好處理另一則訊息。
強烈建議您能夠設定這樣的 接收順序 ,因為它會導致顯著的效能降低。 許多,如果不是大多數,使用者案例不需要排序訊息。 暫停訊息也可以中斷排序。 在此情況下,究竟該怎麼做是應用程式相依的,因此配接器要做的最好是為使用者提供設定點。
在已排序的案例中,有些客戶表示他們寧願停止處理,也就是停用配接器,而不是中斷排序。 支援已排序接收的 MQSeries 配接器會將此選項提供給使用者。
處理 Send-Specific 批次錯誤
處理傳送重試和批處理
以下是傳送端批處理的典型範例:
BizTalk Server 會將一批訊息提供給配接器。
當配接器判斷它已正確地將訊息送達目的地時,它會在 BizTalk Server 上執行刪除操作,以指出工作已完成。 (一如往常,可以任意批處理數個刪除訊息以改善效能。
如果傳送端配接器無法處理訊息,則它可能會使用該訊息執行下列其中一項動作:
配接器應告知 BizTalk Server 它要求重新嘗試處理此訊息。 BizTalk Server 不會自動重試訊息。 BizTalk Server 會保留重試次數,而且可以在訊息內容中看到此計數。
配接器可能會判斷它無法處理訊息。 在此情況下,配接器可能會將訊息移至下一個傳輸。 配接器會在 Batch 物件上使用 MoveToNextTransport 呼叫執行此動作。
配接器可能會將訊息移至暫止佇列。
配接器會決定訊息會發生什麼事。 不過,建議您讓配接器以一致的方式運作,因為這可讓 BizTalk Server 安裝更容易支援。
強烈建議轉接器的行為應如以下所述。 BizTalk Server 隨附的配接器的行為如下。
批次傳送錯誤處理的建議做法
傳送配接器會接收一些訊息,並將其提交至 BizTalk Server。
針對每個成功的訊息,配接器應該刪除 BizTalk Server 上的該訊息。 所有回 BizTalk Server 的通訊都是透過批次完成,而且可以批處理刪除。 這些批次不必是 BizTalk Server 在適配器上建立的批次。 如果有任何回應訊息(如 SolicitResponse 案例中所示),則應該將回應訊息連同相關的刪除送回 BizTalk Server(使用 SubmitResponse)。
如果配接器中的訊息處理失敗,請檢查重試計數。
如果重試計數未超過,請將訊息重新提交至 BizTalk Server,記得在訊息上設定重試時間。 訊息內容會提供重試計數,以及配接器應使用的重試間隔。
如果已超過重試次數,配接器應嘗試藉由使用MoveToNextTransport來移動訊息。 重新提交和 MoveToNextTransport 訊息可以與同批次中的刪除訊息混合回 BizTalk Server。 這不是必要的,但可能是一個有用的步驟。
重新提交和 MoveToNextTransport 是配接器處理失敗的方法。 但在處理失敗時可能會發生失敗。 在此情況下,在處理 BizTalk Server 的回應時(在 BatchComplete 方法中),配接器必須針對 BizTalk Server 建立另一個批次,以指出如何處理該失敗。
當處理涉及另一個失敗過程中的失敗時,請遵循下列步驟:
如果重新提交失敗,請使用 MoveToNextTransport。
如果 MoveToNextTransport 失敗,請使用 MoveToSuspendQ。
您必須持續在 BizTalk Server 上建立批次,直到您在 BizTalk Server 上收到成功的回覆為止。
訊息內容屬性的串行化
指派給訊息內容屬性的所有對象都必須可串行化。 否則傳訊引擎會擲回類型 E_NOINTERFACE例外狀況。 這個返回值模棱兩可地表示一個無法序列化的物件嘗試賦予訊息上下文。