次のトピックでは、アダプターの適切なシャットダウンに関するガイダンスを提供します。
アダプターの終了
メッセージング エンジンがシャットダウンすると、 IBTTransportControl が呼び出されます。各インプロセス アダプターで終了 します。 このメソッドが返された後、BizTalk Server はアダプターを破棄します。 ネイティブ アダプターの場合、これはすぐに発生しますが、マネージド アダプターの場合は、.NET ガベージ コレクション プロセスが原因で、これが発生した場合の決定性が低下します。 アダプターは Terminate でブロックし、破棄する準備ができるまで必要なクリーンアップ作業を行う必要があります。
分離受信アダプターの終了
分離受信アダプターは、BizTalk サービスでホストされていないため、 Terminate が呼び出されません。 代わりに、 IBTTransportProxy を呼び出す必要があります。TerminateIsolatedReceiver を使用して、シャットダウンしようとしていることをメッセージング エンジンに通知します。
Marshal.ReleaseComObject を使用して COM オブジェクトをクリーンアップする
COM オブジェクトを使用するマネージド コードを記述する場合、共通言語ランタイム (CLR) は COM オブジェクトへの参照を保持するプロキシ オブジェクトを生成します。 プロキシ オブジェクトはマネージド オブジェクトであり、ガベージ コレクションの通常の規則に従います。 問題は、ガベージ コレクターが .NET ランタイムが割り当てたメモリのみを認識し、COM オブジェクトを認識しないという点で発生します。 プロキシ オブジェクトが小さいため、CLR ガベージ コレクターが認識していないため、大きな COM オブジェクトがメモリ内に残っている可能性があります。
この問題を回避するには、基になる COM オブジェクト (特に IBTTransportBatch オブジェクト) の終了時に明示的に解放します。 これを行うには、 Marshal を呼び出します。ReleaseComObject。
注
ReleaseComObject は、残りの参照の数を返し、この戻り値が 0 の場合にのみ COM オブジェクトを解放します。 多くの場合、 ReleaseComObject は、オブジェクトが確実に解放されるようにループで呼び出されます。 完了したら、このオブジェクトに対して SuppressFinalize を呼び出す必要があります。これは、最終処理するものがないためです。 最後の手順の 1 つは、これが実際に COM オブジェクトであるかどうかを確認することです。
次のコードは、上記のプロセスを示しています。
if (Marshal.IsComObject (batch))
(
While (0 <Marshal.ReleaseComObject(batch)
;
GC.SuppressFinalize (batch);
GetBatch から返される IBTTransportBatch オブジェクトを明示的に解放すると、パフォーマンスが大幅に向上する可能性があります。
アダプターを閉じるときに常に Terminate を使用する
BizTalk Server でコードをアダプターとして認識するには、 IBTTransportControl というインターフェイスを実装する必要があります。 このインターフェイスは、BizTalk Server がアダプターと通信する方法を定義し、次のように定義します。
public interface IBTTransportControl
{
void Initialize(IBTTransportProxy transportProxy);
void Terminate();
}
インターフェイスには、 Initialize と Terminate の 2 つのメソッドが含まれています。
初期化する
BizTalk Server は、アダプター アセンブリを読み込んだ後に Initialize メソッドを呼び出します。 これにより、トランスポート プロキシ (BizTalk Server のメイン ハンドル) がアダプターに渡されます。 Initialize の実装は、トランスポート プロキシをメンバー変数に格納するだけです。
終了する
BizTalk Server は、サービスのシャットダウン時に Terminate メソッドを呼び出して、アダプターですべてのバッチの実行を完了する時間を与えます。 これにより、 Terminate メソッドの実装がはるかに複雑になります。
保留中の処理が完了するまで、アダプターは Terminate 呼び出しから戻らてはなりません。 BizTalk Server が Terminate を呼び出すとき、アダプターは現在のすべてのタスクを停止し、新しいタスクを開始しないようにする必要があります。
Terminate はサービスのシャットダウンの一部として呼び出されるため、サービス コントロール マネージャーは、アダプターが Terminate で永続的にブロックした場合にプロセスを終了します。 この場合、BizTalk Server サービスを停止すると、サービス コントロール マネージャーからの警告が表示されます。 可能であれば、このようにアダプターを途中で終了しないようにしてください。 アダプターが終了プロセスを適切に処理せず、プロセスのシャットダウンが開始されたときにスレッドがまだ実行されている場合は、シャットダウン時に BizTalk Server からのアクセス違反が発生することがあります。
BizTalk Server へのインターフェイスの非同期性のため、負荷が高い場合は多数のバッチが存在するため、スレッドは引き続き実行される可能性があります。 Terminate 呼び出しは、続行する前に、アダプターが BizTalk Server で正常に実行されたすべてのバッチの終了を待機するように実装する必要があります。 バッチの結論は、BizTalk Server からの BatchComplete コールバックによって通知されます。 Terminate 呼び出しは、保留中のすべての BatchComplete が発生するまで待機する必要があります。 ただし、バッチの実行は成功している必要があります。 つまり、 IBTTransportBatch::Done の呼び出しは失敗してはなりません。 IBTTransportBatch::Done の呼び出しが失敗した場合、バッチ コールバックはありません。
アダプターに同期コードを追加する必要があることに気付いた後、実装はかなり簡単です。
簡単な方法の 1 つは、ワーカー スレッドの enter メソッドと leave メソッドと、スレッドがまだ保護された実行内にある間にブロックする terminate メソッドを含む複合同期オブジェクトを実装することです。 (なお、このソリューションは、ワーカー スレッドをリーダーとして、 terminate メソッドをライターと考えることができる、使い慣れた複数リーダーの単一ライター構造によく似ています)。
terminate メソッドは次のとおりです。
void terminate ()
{
this.control.Terminate();
}
ワーカー スレッドごとに次の手順を実行します。
If (!this.control.Enter())
return; // we can’t enter because Terminate has been called
try
{
// create and fill batch
batch.Done();
}
catch (Exception)
{
// we are not expecting a callback
This.control.Leave();
}
BizTalk Server からのコールバックで、次の手順を実行します。
batchComplete (…)
{
// the callback from BizTalk Server
// process results
this.control.Leave();
}
BizTalk Server には、基本アダプターのサンプルにControlledTermination.csサンプル コードが付属しています。ここに記載されている同期メカニズムが示されています。