locked
What can SqlWorkflowInstanceStore do for me? RRS feed

  • Question

  • Greetings,

    (1) How can I get all persisted instances from the store, which  are ready to be loaded and run? I have three instances like that, but WaitForEvents() always gets me just one, although the method returns a List<InstancePersistenceEvent>.  This is what I have:

                List<Guid> readyToRun = new List<Guid>();

                bool timeout = false;
                try
                {
                    List<InstancePersistenceEvent> events = _wfstore.WaitForEvents(_wfh, TimeSpan.FromSeconds(5));
                    foreach (InstancePersistenceEvent evt in events)
                    {
                        if (evt == HasRunnableWorkflowEvent.Value)
                        {
                            TryLoadRunnableWorkflowCommand cmd = new TryLoadRunnableWorkflowCommand();
                            InstanceView iview = _wfstore.Execute(_wfh, cmd, TimeSpan.FromSeconds(5));
                            readyToRun.Add(iview.InstanceId);
                        }
                        else if (evt is HasActivatableWorkflowEvent)
                        {
                        }
                    }
                }
                catch (TimeoutException)
                {
                    return Guid.Empty;
                }

    Will WaitForEvents() ever return more than one? Under what scenario? And then, how having multiple events relates to the TryLoadRunnableWorkflowCommand retrieving a single InstanceView?

    My assumption is that WaitForEvents() returns events for a single persisted instance, so I have to put the above in a loop to get them all. Please confirm.

    Also, what's the order the instances get picked up? Do I have any say in this?

    (2) Now that I have an InstanceView, how do I figure from it which workflow definition (Activity) to use so I can instantiate a WorkflowApplication(Activity), Load() and Run() it? Do I keep my own mapping between an Activity and all of its running instances?

    (3) How do I use the InstanceHandle? It has a Free() method. When must/should/may I call it? After the above code for getting a runnable instance I have to call _wfh.Free(), otherwise my Load() on the WorkflowApplication object fails with InstanceHandleConflictException ("The execution of an InstancePersistenceCommand was interrupted because another valid InstanceHandle holds a lock on instance 'bbf4ad46-62be-421d-bfb3-db051c49ad84', indicating that a non-stale copy of the instance is already loaded. The loaded copy of the instance and its associated InstanceHandle should be used or unloaded.")

    (4) Can I reuse a single SqlWorkflowInstanceStore instance for all my persistence store needs - all WorkflowApplication instances, any InstancePersistenceCommand-s I Execute(), etc.

    Thank you!

    tjk :)

    Tuesday, April 20, 2010 9:16 PM

All replies

  • Hi,

    There is another thread with a similar discussion here:

    http://social.msdn.microsoft.com/Forums/en-US/wfprerelease/thread/49dfd5a8-f937-4787-b4c2-eae1cf7e868c

    There is a new sample in the WF/WCF sample package that covers loading runnable instances available here:

    http://www.microsoft.com/downloads/details.aspx?FamilyID=35ec8682-d5fd-4bc3-a51a-d8ad115a8792&displaylang=en

     

    Once you extract the samples the path is this:  WF_WCF_Samples\WF\Basic\Services\AbsoluteDelay\CS\AbsoluteDelay

    The documentation for this sample has not been published so I don't have a link for that, but it shows how to load the runnable instances.

    Let me check into getting specific answers for your 4 questions, but possibly this new sample may provide some insight while I am looking into this.

    For #4, do you mean a single database to use from your different hosts? Or do you mean a single instance of the object that you use among the different instances of WorkflowApplication that you have running in your host? if it is the second, then the answer is yes, the Absolute Delay sample uses a single InstanceStore throughout the lifetime of the app, and several different WorkflowApplication instances.

    Steve Danielson [Microsoft]
    This posting is provided "AS IS" with no warranties, and confers no rights.
    Use of included script samples are subject to the terms specified at http://www.microsoft.com/info/cpyright.htm

     

    Tuesday, April 20, 2010 10:36 PM
  • Hi!

    Yes, single database for persistence with a single instance store. So (4) is confirmed as I expected.

    I've read through that thread, and have already seen the sample, on which I based my code. But that does not show how I can figure out which workflow application to instantiate based on the InstanceView loaded. In the samples and in my code the workflow definition is always the same. For that reason, the sample does not even use TryLoadRunnableWorkflowCommand() to get an InstanceView, but blindly calls LoadRunnableInstance() on the WorkflowApplication, because it knows it can't by any other.

    I need to be able to do this:

    List<InstancePersistenceEvent> events =GetAllEvents(MyInstanceStore);
    foreach(HasRunnableWorkflowEvent in events)
      StoreInstanceId(ListOfReadyToRunInstances)

    foreach(InstanceId in ListOfReadyToRunInstances)
      Activity wfDefinition = LoadWorkflowDefinition(InstanceId)
      WorkflowApplication wfApp = new WorkflowApplication(wfDefinition)
      wfApp.Load(InstanceId)
      wfApp.Run

    Also, about (3) and the instance handle. Here's what I have:

                while (true)
                {
                    //InstanceHandle ih = _wfstore.CreateInstanceHandle();
                    try
                    {
                        List<InstancePersistenceEvent> events = _wfstore.WaitForEvents(_wfh, TimeSpan.FromSeconds(5));
                        //List<InstancePersistenceEvent> events = _wfstore.WaitForEvents(ih, TimeSpan.FromSeconds(5));
                        foreach (InstancePersistenceEvent evt in events)
                        {
                            if (evt == HasRunnableWorkflowEvent.Value)
                            {
                                TryLoadRunnableWorkflowCommand cmd = new TryLoadRunnableWorkflowCommand();
                                InstanceView iview = _wfstore.Execute(_wfh, cmd, TimeSpan.FromSeconds(5));
                                readyToRun.Add(iview.InstanceId);
                            }
                            else if (evt is HasActivatableWorkflowEvent)
                            {
                            }
                        }
                    }
                    catch (TimeoutException)
                    {
                        break;
                    }
                    finally
                    {
                    }
                }

    On the second loop, the Execute() throws:

    System.InvalidOperationException was unhandled
      Message=The instance persistence system is unable to process an invalid InstancePersistenceCommand.  The command requires an unbound handle, but the InstanceHandle is already bound to an instance.

    So how long can I use my _wfh? Do I have to get a new one every time I execute a different command? When do I Free() them?

    Thank you.

    tjk :)

    Wednesday, April 21, 2010 3:53 PM
  • You will get 1 HasRunnableWorkflowEvent regardless of the total number of instances that are ready to run. This event remains signaled untill there are not more instances left in a ready to run state.

    There's no guarantee what order instances will be returned in from the TryLoadRunnable call - only that the instance is ready to run and not locked by a host.

    There is a HasActivatableWorkflowEvent that we use to restart WAS based hosts to recover ready to run instances. This doesn't work with WorkflowApplication in they way that I suspect you want.

    You're potntially looking at writing some custom code to go directly to the DB to do the instance Id -> workflow definition mapping.

    You can use the owner instance handle each time you query for events, but you need a new instance handle when you issue the TryLoad command to the store. Free it when the instance has been completed/unloaded.

    • Proposed as answer by Ruppert Koch Tuesday, May 18, 2010 5:10 PM
    Wednesday, April 21, 2010 10:22 PM
  • Hi!

    Thank you for the insights.

    So, to have loading/unloading work I start with:

        _wfstore = new SqlWorkflowInstanceStore(connString);
        _wfh = _wfstore.CreateInstanceHandle();

    But then I *must* do the following or else it won't work:
        // create these XNames
        XName WorkflowHostTypePropertyName = XNamespace.Get("urn:schemas-microsoft-com:System.Activities/4.0/properties").GetName("WorkflowHostType");
        XName wfHostTypeName = XName.Get("Version1", "MyNameSpace");
        
        // add them as metadata to the command to get an owner
        cmdOwner.InstanceOwnerMetadata.Add(WorkflowHostTypePropertyName, new InstanceValue(wfHostTypeName));
        
        // make some dictionary with them and ...
        _wfScope = new Dictionary<XName, object>
        {
             { WorkflowHostTypePropertyName, wfHostTypeName }
        };
        //...later use it for my workflow instance
        WorkflowApplication app = new WorkflowApplication(GetDefinition());
        app.InstanceStore = _wfstore;
        app.AddInitialInstanceValues(_wfScope);

    So now, the wfHostTypeName is associated with the instance owner, which in turn is associated with the instance store, which is used to load/unload my workflow instance which is also associated with wfHostTypeName. For wfHostTypeName the comments say "The unique name should change whenever the implementation of the workflow changes...". Does that mean that the instance store is only good to persist workflow instances of a single workflow definition? Because it looks I'll need another SqlWorkflowInstanceStore that's associated with a different XName. And that makes asking for and loading any runnable instance difficult to do.

    If the above assumption is true, does it extend to the database model itself? I.e. - the persistent database is not able to support instances of different workflow definitions.

    My scenario is that I have hundreds of distinct workflow definitions (Activity00, Activity01, ...) and each could will have tens of instances running at any given time. I wanted in a single call to retrieve all the ones that a ready to be resumed, regardless of owner, and XName stuff. It seems the SqlWorkflowInstanceStore is extremely limited in functions, and I need to write a custom InstanceStore.

    tjk :)
    Thursday, April 22, 2010 3:20 PM
  • One SWIS can support many owners, so you do not need more than one SWIS.

    The part this is missing for your scenario is the ability to get the instances IDs that are ready to run for owners other then the current owner. This is available for WAS activated hosts but not for WorkflowApplication.

    It looks easiest for you to look at the Instances view to look for instances with expired timers, and then use the ServiceDeploymentId to use the ServiceDeployments view to get the Name and Namespace of the service that you need to start a WorkflowApplication host for.

    Thursday, April 22, 2010 10:56 PM
  • Currently in the database I have two instances that could be loaded and run (i.e. PendingTimer values are in the past). But I have no records in the ServiceDeploymentsTable, and InstancesTable.ServiceDeploymentId is NULL for both instances. What will make SWIS add service deployment records and still using WorkflowApplication for hosting?

    Thank you.

    tjk :)

    Friday, April 23, 2010 4:49 PM
  • SWIS does not populate the SeriveDeploymentTable if you host your workflow in WorkflowApplication (see http://msdnstage.redmond.corp.microsoft.com/en-us/library/ee364724.aspx).
    Wednesday, May 5, 2010 6:32 PM
  • SWIS does not populate the SeriveDeploymentTable if you host your workflow in WorkflowApplication (see http://msdnstage.redmond.corp.microsoft.com/en-us/library/ee364724.aspx).


    Here is the link to that topic from Ruppert's post:

    http://msdn.microsoft.com/en-us/library/ee364724.aspx

    Steve Danielson [Microsoft]
    This posting is provided "AS IS" with no warranties, and confers no rights.
    Use of included script samples are subject to the terms specified at http://www.microsoft.com/info/cpyright.htm

     

    Wednesday, May 5, 2010 10:29 PM