WF4实例持久化命令被中断。

3
我有一个运行工作流的Windows服务。这些工作流是从数据库(用户可以使用重新托管的设计师定义自己的工作流)加载的XAML文件。它配置了一个 SQLWorkflowInstanceStore 实例,以在进入空闲状态时持久化工作流(基本上是从Microsoft的WCF/WF示例中的\ControllingWorkflowApplications示例代码派生而来)。
但有时会出现以下错误: System.Runtime.DurableInstancing.InstanceOwnerException:由于所有由此所有者锁定的实例的内存副本已过期并且应该与InstanceHandles一起丢弃,因此中断了InstancePersistenceCommand的执行,因为所有者ID“a426269a-be53-44e1-8580 -4d0c396842e8”的实例所有者注册变得无效。通常,最好通过重新启动主机来处理此错误。
我一直在努力找出原因,但在开发中很难复现,在生产服务器上,我偶尔会遇到此问题。我发现一个提示:当我查看LockOwnersTable时,我发现LockOnwersTable lockexpiration设置为01/01/2000 0:0:0,不再更新,而在正常情况下,应根据主机锁续订周期每x秒更新一次。
那么,为什么SQLWorkflowInstanceStore停止更新此LockExpiration,并如何检测其原因?
3个回答

1

这是一个旧帖子,但我刚刚遇到了相同的问题。

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

工作流基础设施的某些方面仍然文档不够完善;持久性框架就是其中之一。以下代码片段通常用于设置实例存储:

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;
}

与错误信息建议的主机重启相比,它肯定更少侵入性。


虽然这个链接可能回答了问题,但最好在此处包含答案的基本部分并提供参考链接。如果链接页面更改,仅有链接的答案可能会失效。- 来自审查 - Rosário Pereira Fernandes
Rosario,你说得完全正确。我编辑了我的回答,引用了整个帖子。 - Marco Zecca

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


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();

希望这能帮到你


只需尝试从Microsoft WF示例中的Basic文件夹中获取ControllingWorkflowApplications样本。启动Parallel1.xaml(包含在样本中)。然后停止SQL Server服务至少30秒钟。重新启动SQL Server并尝试恢复书签,它将中止工作流程... - rekna
@rekna - 我们遇到了同样的问题 - 你找到解决方法了吗? - Dave Clausen
1
很不幸,我现在仍未收到微软的回复,虽然我已经向他们提出了一个问题。目前,我正在使用一个解决方法(远非完美),该方法监视工作流数据库以查明锁定期限是否仍然有效,如果无效,则重新启动工作流实例。我真的不理解这背后的逻辑。我希望我能编写一个自定义实例存储,但微软使它变得过于复杂。从现有实例存储中派生实际上是不可能的。 - rekna
感谢 @rekna。请注意,此文章提到了一个示例 XML InstanceStore(来自 MS 示例)和一个示例内存 InstanceStore。也许您可以从中获得一些帮助。 http://social.msdn.microsoft.com/Forums/en-US/2b4ecebb-3442-4346-80e4-fecbf05cad47/developing-of-a-custom-instancestore-errors - Dave Clausen
当升级到新版本的WF时(例如从4.0到4.5),事情可能会发生变化,因此我有点不愿意完全自己编写。这是一种风险。更好的方法是,如果InstanceStore可以轻松扩展,那么只需更改所需的行为即可...不幸的是,情况并非如此。 - rekna

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接