WF4 InstancePersistenceCommand被中断

时间:2013-05-19 20:16:29

标签: persistence workflow-foundation-4

我有一个Windows服务,正在运行工作流程。工作流是从数据库加载的XAML(用户可以使用重新设计的设计器定义自己的工作流)。它配置了一个SQLWorkflowInstanceStore实例,以便在变为空闲时保留工作流。 (它基本上来自Microsoft的WCF / WF样本的\ ControllingWorkflowApplications中的示例代码。)

但有时我会收到如下错误:

System.Runtime.DurableInstancing.InstanceOwnerException:InstancePersistenceCommand的执行被中断,因为所有者ID'a426269a-be53-44e1-8580-4d0c396842e8'的实例所有者注册已失效。此错误表示此所有者锁定的所有实例的内存中副本已过时,应与InstanceHandles一起丢弃。通常,最好通过重新启动主机来处理此错误。

我一直在努力找到原因,但是在开发中很难重现,但在生产服务器上,我偶尔会得到它。我发现一个提示:当我查看LockOwnersTable时,我发现LockOnwersTable lockexpiration设置为01/01/2000 0:0:0并且它不再被更新,而在正常情况下应该每x秒更新一次主机锁更新期......

那么,为什么SQLWorkflowInstanceStore会停止更新此LockExpiration,以及如何检测它的原因?

3 个答案:

答案 0 :(得分:1)

这是因为有后台程序在运行并尝试每隔30秒扩展一次实例存储的锁定,并且一旦连接失败连接到SQL服务,它就会将此实例存储标记为无效。 如果从[LockOwnersTable]表中删除实例存储记录,则可以看到相同的行为。 建议的解决方案是,当此异常触发时,您需要释放旧的实例存储并初始化新的

public class WorkflowInstanceStore : IWorkflowInstanceStore, IDisposable
{
    public WorkflowInstanceStore(string connectionString)
    {
        _instanceStore = new SqlWorkflowInstanceStore(connectionString);

        InstanceHandle handle = _instanceStore.CreateInstanceHandle();
        InstanceView view = _instanceStore.Execute(handle, 
            new CreateWorkflowOwnerCommand(), TimeSpan.FromSeconds(30));
        handle.Free();

        _instanceStore.DefaultInstanceOwner = view.InstanceOwner;
    }

    public InstanceStore Store
    {
        get { return _instanceStore; }
    }

    public void Dispose()
    {
        if (null != _instanceStore)
        {
            var deleteOwner = new DeleteWorkflowOwnerCommand();
            InstanceHandle handle = _instanceStore.CreateInstanceHandle();
            _instanceStore.Execute(handle, deleteOwner, TimeSpan.FromSeconds(10));
            handle.Free();
        }
    }

    private InstanceStore _instanceStore;
}

您可以在此链接中找到创建实例存储句柄的最佳做法 Workflow Instance Store Best practices

答案 1 :(得分:1)

这是一个老话题,但我偶然发现了同样的问题。

Damir's Corner建议在调用实例存储之前检查实例句柄是否仍然有效。我在此引用整篇文章:

  

Workflow Foundation的某些方面仍然记录不完整;持久性框架就是其中之一。以下代码段通常用于设置实例存储:

var instanceStore = new SqlWorkflowInstanceStore(connectionString);
instanceStore.HostLockRenewalPeriod = TimeSpan.FromSeconds(30);
var instanceHandle = instanceStore.CreateInstanceHandle();
var view = instanceStore.Execute(instanceHandle, 
    new CreateWorkflowOwnerCommand(), TimeSpan.FromSeconds(10));
instanceStore.DefaultInstanceOwner = view.InstanceOwner;
  

很难找到所有这一切的详细解释   做;说实话,通常没有必要。至少不是,   直到你开始遇到问题,例如InstanceOwnerException:

     

InstancePersistenceCommand的执行被中断,因为   所有者注册所有者ID   ' 9938cd6d-a9cb-49ad-a492-7c087dcc93af'已变得无效。这个错误   表示由此锁定的所有实例的内存中副本   老板已经变得陈旧,应该随便丢弃   InstanceHandles。通常,最好通过重新启动来处理此错误   主持人。

     

该错误与HostLockRenewalPeriod属性密切相关   它定义了获取的实例句柄在没有的情况下有效的时间   更新。如果您尝试在实例存储时监视数据库   如果实例化了有效的实例句柄,您会注意到   [System.Activities.DurableInstancing]。[ExtendLock]被调用   定期。该存储过程负责更新   处理。如果由于某种原因无法在指定范围内调用它   HostLockRenewalPeriod,将抛出上述异常   当试图坚持工作流程时。这种情况的典型原因是   由于维护或联网而暂时无法访问数据库   问题。它不是经常发生的事情,但它必然会受到影响   如果你有一个很长的实例存储,例如一直在   运行工作流主机,例如Windows服务。

     

幸运的是,一旦你解决了这个问题并不是那么困难   知道它的原因。在使用实例存储之前,您应该   如果手柄仍然有效,请务必检查;并更新它,如果不是:

if (!instanceHandle.IsValid)
{
    instanceHandle = instanceStore.CreateInstanceHandle();
    var view = instanceStore.Execute(instanceHandle, 
        new CreateWorkflowOwnerCommand(), TimeSpan.FromSeconds(10));
    instanceStore.DefaultInstanceOwner = view.InstanceOwner;
}
  建议,它确实比主机重启更具侵入性   通过错误消息。

答案 2 :(得分:0)

您必须确定所有者用户的到期时间

这里我是如何处理这个问题的

     public SqlWorkflowInstanceStore SetupSqlpersistenceStore()
    {
        SqlWorkflowInstanceStore sqlWFInstanceStore = new SqlWorkflowInstanceStore(ConfigurationManager.ConnectionStrings["DB_WWFConnectionString"].ConnectionString);
        sqlWFInstanceStore.InstanceCompletionAction = InstanceCompletionAction.DeleteAll;
        InstanceHandle handle = sqlWFInstanceStore.CreateInstanceHandle();
        InstanceView view = sqlWFInstanceStore.Execute(handle, new CreateWorkflowOwnerCommand(), TimeSpan.FromSeconds(30));
        handle.Free();
        sqlWFInstanceStore.DefaultInstanceOwner = view.InstanceOwner;
        return sqlWFInstanceStore;
    }

以及如何使用此方法

     wfApp.InstanceStore = SetupSqlpersistenceStore();

希望得到这个帮助