【问题标题】:Windows Workflow: Why do they get stuck in persistence?Windows 工作流:为什么他们会陷入持久性?
【发布时间】:2009-07-29 17:35:50
【问题描述】:

我有一个使用 SQL 持久性的 Windows Workflow 实例,托管在 Web 运行时中,因为工作流是由 ASP.NET 表单提交启动的。它大部分时间都运行良好,但我注意到我必须踢东西的情况:

我注意到 nextTimer 已经过期了,即使是几个小时。有时 ownerID 和ownedUntil 字段在持久性数据库中为空,有时不是。 “unlocked”和“blocked”字段始终都是“1”。

...然后工作流运行时不会将其恢复,直到我将“所有者”字段清空(如果它们已填充并通过循环启动应用程序池),此后一切顺利大部分。没有错误(我在所有内容周围都有 try/catch 块,并将捕获的任何内容写到跟踪文件中),所以不是这样。

导致持久性的延迟活动都设置为一分钟,运行时的所有权持续时间也是 60 秒。它卡住的代码应该总是不到一分钟。

在我写这篇文章时,我很好奇应用程序池/应用程序域的回收是否会导致它......当工作流尝试调用运行时中的任何方法时,它正忙于启动应用程序域/应用程序池并且可能在 60 秒的所有权期限内泄漏。这听起来似乎很合理,这会导致它无法正常补水吗?

除了偏离轨道之外,我看到的这种行为可能是什么原因造成的?我不想通过解除卡住的工作流程来每天照看运行时。

【问题讨论】:

    标签: workflow-foundation


    【解决方案1】:

    很可能应用程序域回收是您问题的很大一部分。 IIS 将在最后一个请求完成后立即回收 AppDomain。但是,它不会将在另一个线程上运行的代码视为该请求的一部分。这是在 IIS 中托管时使用 ManualWorkflowSchedulerService 的主要原因之一。但是当您使用活动计时器选项时,它仍然使用后台线程来执行工作流活动。

    还要确保在工作流空闲时立即卸载它们。最简单的方法是使用 SqlWorkflowPersistenceService 上的 UnloadOnIdle 设置。

    PersistenceService 仅在启动时检查所有权过期的工作流。因此,很可能重新启动 IIS 工作进程也将重新启动旧工作流,而无需任何额外工作。但由于这是新问题的情况......清除旧所有权也应该可以解决问题。在这种情况下,PersistenceService 应该在下次重新加载工作流。唯一的技巧是知道哪个 runitme ID 是旧的,哪个不是旧的(持有该值的属性不是公共的)。

    要确保的另一件事是重新加载 IIS 工作进程。如果不这样做,则没有 WF 运行时,因此它无法检查过期的计时器。听起来您已经涵盖了这一点,但以防万一。

    【讨论】:

    • 优秀的文章,明天我会尽可能多地尝试并报告。
    • 标记为已接受,因为它涵盖了很多内容,感谢您提供信息!它最终成为的是所有权时间。我提高了 instanceOwnershipDuration 以允许完全执行它试图为每个加载的活动做的任何事情,并且从那以后它没有出现故障。
    【解决方案2】:

    您是否检查过数据库和网络服务器上的时钟(如果它们不是同一台服务器)?我之前在工作流中遇到过类似的问题,根本原因是数据库和网络服务器时钟不同步。

    【讨论】:

    • 我没有想到这一点,但检查了一下,它们与第二个同步。好主意,谢谢!
    【解决方案3】:

    工作流实例被锁定到一个运行时(因此多个工作流运行时可以共享一个数据库,而无需同时处理实例)。当 AppDomain 回收时,应停止 Runtime,导致实例解锁

    这可能是多余的,我没有检查,但它有助于解锁工作流实例:

    AppDomain.CurrentDomain.DomainUnload += ((sender, args) =>
                                                 {
                                                     if (_runtime.IsStarted)
                                                         _runtime.StopRuntime();
                                                 });
    AppDomain.CurrentDomain.ProcessExit += ((sender, args) =>
                                                {
                                                    if (_runtime.IsStarted)
                                                        _runtime.StopRuntime();
                                                });
    

    【讨论】:

    • 我在 global.asax 的“Application_End”函数中做了类似的事情,在那里停止了运行时。我们的方法是做同一件事的两种方式吗?从未使用过上述调用。感谢您的意见,+1!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多