How to write a lengthy job to call web services in WF 4.0

I created an operation that executes a web request and stores the result in a database. I learned that for these lengthy operations I have to write several different codes so that the thread of the workflow is not blocked.

public sealed class WebSaveActivity : NativeActivity
{
    protected override void Execute(NativeActivityContext context)
    {
       GetAndSave(); // This takes 1 hour to accomplish.
    }
}

How do I rewrite this action to meet the requirements for a long action

+2
source share
2 answers

, , , ThreadPool.QueueUserWorkItem(), , . , . Hangfire , .

EDIT:

(TAP): 1, 2, , , , . , , , . Windows Workflow Foundation - / .

+1

WF. , . , .

. Microsoft SQL Workflow, , SQL, SQL Server.

namespace MySolution.MyWorkflowApp
{
    using System.Activities;
    using System.Activities.DurableInstancing;
    using System.Activities.Statements;
    using System.Threading;

    internal static class Program
    {
        internal static void Main(string[] args)
        {
            var autoResetEvent = new AutoResetEvent(false);
            var workflowApp = new WorkflowApplication(new Sequence());
            workflowApp.InstanceStore = new SqlWorkflowInstanceStore("server=mySqlServer;initial catalog=myWfDb;...");
            workflowApp.Completed += e => autoResetEvent.Set();
            workflowApp.Unloaded += e => autoResetEvent.Set();
            workflowApp.Aborted += e => autoResetEvent.Set();
            workflowApp.Run();
            autoResetEvent.WaitOne();
        }
    }
}

/, . :

  • -,

:

public sealed class WebSaveActivity : NativeActivity
{
    public InArgument<MyBigObject> ObjectToSave { get; set; }

    protected override bool CanInduceIdle
    {
        get
        {
            // This notifies the WF engine that the activity can be unloaded / persisted to an instance store.
            return true;
        }
    }

    protected override void Execute(NativeActivityContext context)
    {
        var currentBigObject = this.ObjectToSave.Get(context);
        currentBigObject.WorkflowInstanceId = context.WorkflowInstanceId;
        StartSaveOperationAsync(this.ObjectToSave.Get(context)); // This method should offload the actual save process to a thread or even a web method, then return immediately.

        // This tells the WF engine that the workflow instance can be suspended and persisted to the instance store.
        context.CreateBookmark("MySaveOperation", AfterSaveCompletesCallback);
    }

    private void AfterSaveCompletesCallback(NativeActivityContext context, Bookmark bookmark, object value)
    {
        // Do more things after the save completes.
        var saved = (bool) value;
        if (saved)
        {
            // yay!
        }
        else
        {
            // boo!!!
        }
    }
}

WF, , - .

, . , StartSaveOperationAsync - , :

public static void StartSaveOperationAsync(MyBigObject myObjectToSave)
{
    var targetQueue = new MessageQueue(".\private$\pendingSaveOperations");
    var message = new Message(myObjectToSave);
    targetQueue.Send(message);
}

, . , :

internal static void PollQueue()
{
    var targetQueue = new MessageQueue(@".\private$\pendingSaveOperations");
    while (true)
    {
        // This waits for a message to arrive on the queue.
        var message = targetQueue.Receive();
        var myObjectToSave = message.Body as MyBigObject;

        // Perform the long running save operation
        LongRunningSave(myObjectToSave);

        // Once the save operation finishes, you can resume the associated workflow.
        var autoResetEvent = new AutoResetEvent(false);
        var workflowApp = new WorkflowApplication(new Sequence());
        workflowApp.InstanceStore = new SqlWorkflowInstanceStore("server=mySqlServer;initial catalog=myWfDb;...");
        workflowApp.Completed += e => autoResetEvent.Set();
        workflowApp.Unloaded += e => autoResetEvent.Set();
        workflowApp.Aborted += e => autoResetEvent.Set();

        // I'm assuming the object to save has a field somewhere that refers the workflow instance that running it.
        workflowApp.Load(myObjectToSave.WorkflowInstanceId);
        workflowApp.ResumeBookmark("LongSaveOperation", true); // The 'true' parameter is just our way of saying the save completed successfully. You can use any object type you desire here.
        autoResetEvent.WaitOne();
    }
}

private static void LongRunningSave(object myObjectToSave)
{
    throw new NotImplementedException();
}

public class MyBigObject 
{
    public Guid WorkflowInstanceId { get; set; } = Guid.NewGuid();
}

, , .

0

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


All Articles