はじめに
WFチュートリアル 前編、中編ではWFの概要、シーケンシャルワークフロー、ステートマシンワークフローについて解説しました。最終回となる今回は、WFの提供するワークフローの永続化サービスについて解説します。
対象読者
本記事はC#でのプログラミングを行ったことがある方を対象としています。
サンプルを動作させるための環境設定等は『WPF(Windows Presentation Foundation)+XAML入門 前編』をご覧ください。
SQL Serverへのワークフロー永続化
中編で解説したとおり、ステートマシンワークフローを使うアプリケーションでは、複数のワークフローが同時に実行、あるいはイベント待ちをすることになります。サンプルのように数個のワークフローであれば、同時にメモリ上に存在しても問題ありませんが、ワークフローの数が多くなってくると、メモリを圧迫してくるようになるかもしれません。
しかも大抵のケースでは、メモリ上の存在するワークフローのほとんどはイベント待ち状態にあります。イベントが来るまでワークフローは数分、数時間、あるいは数ヶ月ただ待ち続けることになります。イベント待ち状態になったワークフローをずっとメモリ上に保持するのはメモリの無駄となりますので、待ち状態になったワークフローをメモリからディスクなどに永続化させ、イベントが発生するまで待機させることで、メモリを開放することができます。
また、ワークフロー永続化には、耐障害性という側面もあります。ワークフローの実行状態を永続化しておくことで、ワークフローの特定の部分で障害が発生した場合にも、永続化した時点のワークフローをロードして再開することができます。
WFでは、ワークフローの永続化サービスが標準で提供されており、ワークフローの状態管理をすべてWF側の永続化サービスに任せ、プログラマが意識することなく、イベント待ち状態になったワークフローを永続化させることができます。
具体的には、永続化サービスは以下のタイミングで永続化処理を行います。
PersistOnCloseAttribute
属性が付加されたアクティビティが完了するとき(トランザクション範囲を指定するためのTransactionScopeアクティビティなど)- ワークフローが完了するとき
- ワークフローが強制終了するとき
- ワークフローがアイドル状態になるとき
- ワークフローインスタンスの
Unload
メソッド、またはTryUnload
メソッドが呼び出されたとき
多くのケースでは、ワークフロー内でDelayアクティビティを使って時間待ちを行ったり、EventDrivenアクティビティでイベント待ちをしたりする際に、ワークフローがアイドル状態になり、結果的に永続化が行われることになります。
永続化サービスはSystem.Workflow.Runtime.Hosting.WorkflowPersistenceService
という抽象クラスとして定義されています。WFではこのクラスを継承し、SQL Serverに永続化を行うSystem.Workflow.Runtime.Hosting.SqlWorkflowPersistenceService
というクラスが提供されています。
永続化サービスの使い方
では、SQL Serverへの永続化を行うSqlWorkflowPersistenceService
クラスを使って、永続化サービスを試してみましょう。中編で作成した簡易注文管理アプリケーションに永続化サービスを追加し、どのように永続化が行われるかを確認しましょう。
動作環境
SqlWorkflowPersistenceService
クラスはSQL Server 2000/2005およびMSDE 2000上のデータベースに対してワークフローの永続化を行います。この記事ではSQL Server 2005 Express Editionを使用します。
永続化用データベースの作成
Enterprise ManagerやSQL Server Management Studio Expressなどを使って永続化用データベースを作成します。今回はwftestという名前でデータベースを作成します。
次に、永続化用のテーブルを作成します。
「{Windowsフォルダ}\Microsoft.NET\Framework\v3.0\Windows Workflow Foundation\SQL」にある「SqlPersistenceService_Schema.sql」「SqlPersistenceService_Logic.sql」を順に実行してください。これにより、CompletedScopeテーブルとInstanceStateテーブルが作成されます。
永続化サービスの登録
中編で作成したStateMachineWorkflowSampleソリューションを開き、StateMachineWorkflowSampleApplicationプロジェクト(ホスティングWindowsアプリケーション)の「Form1.cs」を開きます。
Form1
クラスのコンストラクタにワークフローランタイムの初期化コードがありますので、そこに永続化サービスの登録処理を追加しましょう。
コンストラクタ内を次のように修正してください。
using System.Workflow.Runtime.Hosting; //ファイル先頭部分に追加
……
public Form1()
{
InitializeComponent();
//ワークフロー ランタイムの生成
workflowRuntime = new WorkflowRuntime();
//(1) データ交換サービス(ExternalDataExchangeService)の生成
ExternalDataExchangeService dataService =
new ExternalDataExchangeService();
//(2) ワークフロー ランタイムへのデータ交換サービスの登録
workflowRuntime.AddService(dataService);
//(3)ExternalDataExchange
属性を持つ自分自身をデータ交換サービスに追加
dataService.AddService(this);
//後編で追加~ここから
string connectionString =
"Initial Catalog=wftest;Data Source=localhost;"
+ " Integrated Security=SSPI;"; //(1) 永続化用データベース接続文字列
bool unloadOnIdle = true;
TimeSpan instanceOwnershipDuration = TimeSpan.MaxValue;
TimeSpan loadingInterval = new TimeSpan(0, 0, 5);
// SQL永続化サービスを追加
WorkflowPersistenceService persistenceService =
new SqlWorkflowPersistenceService(
connectionString,unloadOnIdle,instanceOwnershipDuration,
loadingInterval); //(2) SQL Server永続化サービスの生成
//(3) ワークフロー ランタイムへの永続化サービスの登録
workflowRuntime.AddService(persistenceService);
//(4)ワークフローのイベントごとにメッセージダイアログを表示
workflowRuntime.WorkflowPersisted +=
delegate(object sender, WorkflowEventArgs e)
{ MessageBox.Show(string.Format("Workflow {0} Persisted.",
e.WorkflowInstance.InstanceId)); };
workflowRuntime.WorkflowLoaded +=
delegate(object sender, WorkflowEventArgs e)
{ MessageBox.Show(string.Format("Workflow {0} Loaded.",
e.WorkflowInstance.InstanceId)); };
workflowRuntime.WorkflowUnloaded +=
delegate(object sender, WorkflowEventArgs e)
{ MessageBox.Show(string.Format("Workflow {0} Unloaded.",
e.WorkflowInstance.InstanceId)); };
workflowRuntime.WorkflowIdled +=
delegate(object sender, WorkflowEventArgs e)
{ MessageBox.Show(string.Format("Workflow {0} Idled.",
e.WorkflowInstance.InstanceId)); };
workflowRuntime.WorkflowCompleted +=
delegate(object sender, WorkflowCompletedEventArgs e)
{ MessageBox.Show(string.Format("Workflow {0} Completed.",
e.WorkflowInstance.InstanceId)); };
//後編で追加~ここまで
workflowRuntime.StartRuntime();
}
(1)で、先ほど作成した永続化用データベースへの接続文字列を指定していますので、適宜環境に合わせて修正してください。今回はWindows認証を用いてローカルに存在するSQL Server 2005 Express Editionに接続します。
(2)で、SQL Serverへの永続化サービスであるSqlWorkflowPersistenceServiceを生成しています。第1引数(connectionString)は接続文字列を、第2引数(unloadOnIdle)はアイドル状態のワークフローを永続化するかどうかのフラグを、第3引数(instanceOwnershipDuration)はワークフローの所有権を保持する長さ、第4引数(loadingInterval)は読み込み間隔の長さを指定します。今回はアイドル状態になったワークフローを永続化させるため、第2引数にtrueを指定します。
(3)で、ワークフローランタイムに永続化サービスを登録します。データ交換サービスの登録の場合と同様、AddService
メソッドで登録を行います。
(4)以降は、永続化サービスの登録処理ではなく、ワークフローのイベントごとにメッセージダイアログを表示する処理です。ワークフローの実行に合わせて、どんなイベントが発生しているのかを確認するために追加しています。
イベント名 | 概要 |
WorkflowIdled | ワークフローがアイドル状態になった場合に発生 |
WorkflowPersisted | ワークフローが永続化された場合に発生 |
WorkflowUnloaded | ワークフローがメモリからアンロードされた場合に発生 |
WorkflowLoaded | ワークフローがメモリにロードされた場合に発生 |
WorkflowCompleted | ワークフローが完了した場合に発生 |
以上で永続化サービスの組み込みは完了です。ワークフローランタイムの初期化以外に変更するところはありません。