System.Workflow.Activities.EventDeliveryFailedException を防止する
こんにちは SharePoint サポートの森 (kenmori) です。
SharePoint ワークフローでイベント通知が失敗する現象について、詳細な原因と対処策を記載させていただきます。
ワークフローでイベント通知が失敗した場合、以下のような診断ログが記録され、ワークフローが再開されなくなってしまいます。この現象に陥った場合は、通常、ワークフローを再起動する必要があります。
ワークフローをある程度、複雑に設計した場合にぶつかった方は多いかもしれません。この現象を防ぐために、ワークフロー設計段階で考慮しておく注意事項がございます。今回はイベント通知失敗の原因を記載させていただくとともに、本現象発生を防ぐための対処策をご紹介させていただきます。
診断ログ
Engine RunWorkflow: System.Workflow.Activities.EventDeliveryFailedException: インスタンス ID "998bb571-24fc-4662-801b-b57f6c0047ca" のインターフェイス型 "Microsoft.SharePoint.Workflow.ITaskService" のイベント "OnTaskChanged" は配信できません。 --->
System.NullReferenceException: オブジェクト参照がオブジェクトインスタンスに設定されていません。
場所 Microsoft.SharePoint.Workflow.SPWorkflowHostServiceBase.LoadInstanceData(Guid instanceId, Boolean& compressedData)
場所 Microsoft.SharePoint.Workflow.SPWinOePersistenceService.LoadWorkflowInstanceState(Guid instanceId)
場所 System.Workflow.Runtime.WorkflowRuntime.InitializeExecutor(Guid instanceId, CreationContext context, WorkflowExecutor executor, WorkflowInstance workflowInstance)
場所 System.Workflow.Runtime.WorkflowRuntime.Load(Guid key, CreationContext context, WorkflowInstance workflowInstance)
場所 System.Workflow.Runtime.WorkflowRuntime.GetWorkflow(Guid instanceId)
場所 System.Workflow.Activities.WorkflowMessageEventHandler.EventHandler(Object sender, ExternalDataEventArgs eventArgs)
--- 内部例外スタックトレースの終わり ---
場所 System.Workflow.Activities.WorkflowMessageEventHandler.EventHandler(Object sender, ExternalDataEventArgs eventArgs)
場所 Microsoft.SharePoint.Workflow.SPWinOETaskService.RaiseEvent(SPWinOeWorkflow workflow, SPWorkflowEvent workflowEvent, Object workItem, IPendingWork workHandler)
場所 Microsoft.SharePoint.Workflow.SPWinOeHostServices.Send(SPWinOeWorkflow winoeworkflow, SPWorkflowEvent e)
場所 Microsoft.SharePoint.Workflow.SPWinOeEngine.RunWorkflow(Guid trackingId, SPWorkflowHostService host, SPWorkflow workflow, Collection`1 events, TimeSpan timeOut)
発生原因について
本現象は、1 つのワークフロー インスタンスがイベントによって複数同時に呼び出される際に、タイミングによって非常にまれに発生する場合があります。
ワークフロー ランタイムは実行中のワークフロー インスタンスをトラッキングしております。ワーク バッチを起動する時点でトラッキング一覧に登録し、ワークバッチを終了する時点で一覧より削除します。従って、1 つのワークフローインスタンスにつき、イベントが複数同時発生することによって、タイミングによってはトラッキングに競合を引き起こす可能性があります。
この場合、ランタイム側の処理で、イベントを通知する先であるワークフロー インスタンスがトラッキング中のインスタンス一覧から正しく取得できない (NullReferenceException) ことによりイベント通知が失敗 (EventDeliveryFailedException) すると考えられます。
なお、スレッド間の極めて微妙なタイミングによって発生する事象であるため、環境によっては本事象が全く発生しない場合もあります。
参考情報
タイトル : SharePoint ワークフローのチューニング
アドレス : https://blogs.technet.com/b/sharepoint_support/archive/2011/01/12/sharepoint.aspx
注意事項と対処策
本現象はSharePoint ワークフローを実装するアーキテクチャ上の制限に起因するため、対処するためには上記現象の発生要因をふまえワークフローの設計を変更する必要がございます。
現象の発生を防ぐためには、特にワークフローの設計時に以下の点に注意する必要がございます。
1. ParallelActivity, ReplicatorActivity, ConditionedActivityGroup (CAG) Activity などによって、複数のイベントを同時に待たないようにする。
本現象を最大限引き起こさないようにする対処策としては、イベントを同時実行から順次実行にするよう設計変更するか、ワークフローインスタンスを分割し 1 イベント 1 ワークフロー インスタンスで実行できるよう設計変更する方法があります。
2. ワークフロー インスタンス内で、タスクの作成 (CreateTaskActivity) の次にタスク作成イベント (OnTaskCreated) を配置するなど、インスタンス内でイベントを発生させ、インスタンス内でそのイベントを検知するような実装を避ける。
この実装を必要とする背景として、CreateTaskActivity などを実行した際に、実行結果がワークフローインスタンスのアンロードまでデータとしてコミットされないためにタスクの ID 等が取得できない背景があります。
コミットされた値をどうしても取得したい場合は、永続性サービスの動作を考慮し、ワークフローインスタンスを一度永続化することによって、データを強制的にコミットさせることが可能となります。現実的な対処策としては以下がございます。
対処方法
1) DelayActivityアクティビティなどを使用し、ワークフローをアイドル状態にする
2) PersistOnCloseAttribute属性を使用するカスタム アクティビティを実行する
方法 1) は、時間がかかるデメリットはありますが、開発工数を抑えてご要望を実装できる方法となります。方法 2) は、即座にインスタンスを永続化し、コミットさせることができる方法となります。
いずれかをご検討ください。
なお、2. に関しては以下のサポート技術情報にも紹介されております。
参考情報
タイトル : After you start a workflow on a server that is running SharePoint Services 3.0, you receive an error message that states an error has occurred in the workflow
アドレス : https://support.microsoft.com/kb/970548
(2013/02/04 補足)
類似の現象について、以下のページでご紹介しております。合わせてご参考にしていただけますと幸いです。