繁体   English   中英

使用TPL处理WF 4.0长时间运行活动

[英]Handling WF 4.0 long running activity using TPL

我创建了一个执行Web请求的活动,并将结果存储到数据库中。 通常这个过程大约需要1个小时,这会使工作流引擎表现异常。 我发现对于这些长时间运行的活动,我应该编写一些不同的代码,以便不会阻止工作流引擎线程。

研究一些关于编写长期运行活动的博客,我理解我应该使用Bookmark概念。 但我没有使用TPL和Task任何解决方案。

此代码是否适用于使用Task处理长时间运行的活动?

public sealed class WebSaveActivity : NativeActivity
{
    protected override void Execute(NativeActivityContext context)
    {
        context.CreateBookmark("websave", (activityContext, bookmark, value) =>
        {

        });

        Task.Factory.StartNew(() =>
        {
            GetAndSave(); // This takes 1 hour to accomplish.
            context.RemoveBookmark("websave");
        });

    }

    protected override bool CanInduceIdle 
    {
        get
        {
            return true;
        }
    }
}

不,这不是应该使用书签的方式。 当工作流必须等待来自外部进程的输入时,将使用书签。

例如:我有一个文档审批工作流程,在某个时间点,工作流程必须等待人工审阅者对文档进行确认。 而不是将工作流实例保留在内存中,当ResumeBookmark时,工作流将被运行时空闲并再次激活。

在您的情况下,您的工作流不能被闲置,因为它在其上下文中运行了一个操作。 顺便说一下,这个操作是你的任务,是一个即发即弃的任务,因此WF无法处理关键的失败。

现在,对于可能的解决方案,您可能会考虑让其他进程调用GetAndSave方法,并让该进程最终调用WF上的ResumeBookmark ,以便运行时可以使工作流空闲。 该过程甚至可以与托管您的工作流程的过程相同。

有关示例,请参阅此博文 只是想象一下,而不是等待人类在控制台中输入内容,而是执行长时间运行的任务。

您没有指定活动后的内容,但请注意,当书签恢复时,可以将数据返回到工作流程。 因此, GetAndSave任何结果,即使它只是一个错误代码,您可以用它来决定如何进一步处理工作流中的其他活动。

希望这对你有意义,你会看到我试图概述的可能的解决方案。

编辑关于在WF中使用任务或async / await的快速说明。 AFAIK没有方法可以覆盖返回任务,所以你要么必须使用.Wait().Result来阻止它们,要么忘掉它。 因为如果你不能等待他们在工作流程执行期间会发生坏事,因为在使用Tasks完成其工作之前可能会启动其他活动。

在开发WF运行时时,Tasks的整个概念仍然非常年轻,因此WF运行时没有/不适合它们。

编辑2:示例实现(基于这个优秀的官方文档

您的活动几乎是空的:

public sealed class TriggerDownload : NativeActivity<string>
{
    [RequiredArgument]
    public InArgument<string> BookmarkName { get; set; }

    protected override void Execute(NativeActivityContext context)
    {
        // Create a Bookmark and wait for it to be resumed.
        context.CreateBookmark(BookmarkName.Get(context),
            new BookmarkCallback(OnResumeBookmark));
    }

    protected override bool CanInduceIdle
    {
        get { return true; }
    }

    public void OnResumeBookmark(NativeActivityContext context, Bookmark bookmark, object obj)
    {
       // When the Bookmark is resumed, assign its value to
       // the Result argument. (This depends on whether you have a result on your GetData method like a string with a result code or something)
       Result.Set(context, (string)obj);
    }
}

它向工作流运行时发出信号,表明工作流可以处于闲置状态以及如何恢复工作流。

现在,对于工作流运行时配置:

WorkflowApplication wfApp = new WorkflowApplication(<Your WF>);

// Workflow lifecycle events omitted except idle.
AutoResetEvent idleEvent = new AutoResetEvent(false);


wfApp.Idle = delegate(WorkflowApplicationIdleEventArgs e)
{
    idleEvent.Set();
};

// Run the workflow.
wfApp.Run();

// Wait for the workflow to go idle before starting the download
idleEvent.WaitOne();

// Start the download and resume the bookmark when finished.
var result = await Task.Run(() => GetAndSave());
BookmarkResumptionResult result = wfApp.ResumeBookmark(new Bookmark("GetData"), result);

// Possible BookmarkResumptionResult values:
// Success, NotFound, or NotReady
Console.WriteLine("BookmarkResumptionResult: {0}", result);

我刚看到你的相关问题: 如何编写一个长期运行的活动来调用WF 4.0中的Web服务

另一种方法是将您的活动实现为AsyncCodeActivity

namespace MyLibrary.Activities
{
    using System;
    using System.Activities;

    public sealed class MyActivity : AsyncCodeActivity
    {
        protected override IAsyncResult BeginExecute(AsyncCodeActivityContext context, AsyncCallback callback, object state)
        {
            var delegateToLongOperation = new Func<bool>(this.LongRunningSave);
            context.UserState = delegateToLongOperation;
            return delegateToLongOperation.BeginInvoke(callback, state);
        }

        protected override void EndExecute(AsyncCodeActivityContext context, IAsyncResult result)
        {
            var longOperationDelegate = (Func<bool>) context.UserState;
            var longOperationResult = longOperationDelegate.EndInvoke(result);

            // Can continue your activity logic here.
        }

        private bool LongRunningSave()
        {
            // Logic to perform the save.
            return true;
        }
    }
}

工作流实例保留在内存中,但至少工作流运行时可以处理其正常的调度任务,而其中没有一个线程被长时间运行的进程占用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM