次の方法で共有


アダプターを終了する方法

ここでは、アダプターの適切なシャットダウンに関するガイダンスを提供します。

アダプターの終了

メッセージング エンジンがシャットダウンすると、 IBTTransportControl が呼び出されます。各インプロセス アダプターで終了 します。 このメソッドから制御が戻ると、BizTalk Server はアダプターを破棄します。 この処理は、ネイティブ アダプターの場合は直ちに発生しますが、マネージド アダプターの場合は .NET のガベージ コレクション プロセスが関係するため正確なタイミングを特定できません。 アダプターは Terminate でブロックし、破棄する準備ができるまで必要なクリーンアップ作業を行う必要があります。

分離受信アダプターの終了

分離受信アダプターは、BizTalk サービスでホストされていないため、 Terminate が呼び出されません。 代わりに、 IBTTransportProxy を呼び出す必要があります。TerminateIsolatedReceiver を使用して、シャットダウンしようとしていることをメッセージング エンジンに通知します。

Marshal.ReleaseComObject を使用した COM オブジェクトのクリーンアップ

COM オブジェクトを使用するマネージド コードを記述すると、共通言語ランタイム (CLR) により、COM オブジェクトへの参照を保持するプロキシ オブジェクトが生成されます。 このプロキシ オブジェクトはマネージド オブジェクトであり、ガベージ コレクションの通常のルールが適用されます。 ガベージ コレクターは .NET ランタイムが割り当てたメモリしか参照せず、COM オブジェクトを認識しないことから、1 つの問題が発生します。 それは、プロキシ オブジェクトは小さいため、大きい COM オブジェクトが CLR ガベージ コレクターで認識されずにメモリ内に残される可能性があるという点です。

この問題を回避するには、基になる COM オブジェクト (特に IBTTransportBatch オブジェクト) が完了したら、明示的に解放します。 これを行うには、 Marshal を呼び出します。ReleaseComObject

Note

ReleaseComObject は残りの参照数を返し、この戻り値が 0 の場合にのみ COM オブジェクトを解放します。 多くの場合、 ReleaseComObject はループ内で呼び出され、オブジェクトが確実に解放されます。 完了したら、このオブジェクトに対して SuppressFinalize を呼び出す必要があります。これは、最終処理するものがないためです。 最後の手順として、このオブジェクトが間違いなく 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 の実装は、トランスポート プロキシをメンバー変数に格納するだけです。

Terminate

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 に付属し、ここで説明する同期メカニズムを示します。