WF 4.0 Long-Term Processing Using TPL

I created an operation that executes a web request and stores the result in a database. Usually this process takes about 1 hour, and it forces the workflow mechanism to behave abnormally. I learned that for these lengthy operations I have to write several different codes so that the thread of the workflow is not blocked.

By learning some blogs about writing long-lasting activities, I understand that I should use the concept Bookmark. But I had no solution using TPL and Task.

Is this code correct for handling long running with Tasks?

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;
        }
    }
}
+4
2

: - WF 4.0

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

, , , , .

+1

, , . , .

: , - , . , , , ResumeBookmark.

, . - , , , "--", WF.

, , , GetAndSave, ResumeBookmark WF, . , .

. blogpost. , , , - , .

, , , . , GetAndSave, , , , .

, , , .

async/await WF. AFAIK, , .Wait() .Result . , , - , , .

WF , , 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);
+3

Source: https://habr.com/ru/post/1679529/


All Articles