In part 1 I configured the Persistence store for a WF 4.0 workflow services hosted by WorkflowServiceHost. I showed how the workflow is persisted just before sending a response to a client application and observed the persisted state in the database.
In part 2 I will add a host behavior to persist the workflow based on an Idle time as opposed to before sending the response from the workflow itself, moreover I will also add a host behavior to unload the workflow after a specified time interval thus showing the difference between “just” persisting a workflow and unloading it from memory.
Let’s start by unchecking (disabling) property PersistBeforeSend of the SendReplyToReceive shape. Next add the following code to the Program.cs file of the workflow application just before the “host.Open()” statement:
{
TimeToPersist = TimeSpan.FromSeconds(5),
TimeToUnload = TimeSpan.FromSeconds(20)
});
This code adds a behavior to persist the WF instance after 5 seconds of inactivity and to unload it completely after 20 seconds of inactivity. What’s the difference? Persistence – as explained in Part 1 – persists the workflow state in the DB but keeps the workflow instance running. Unloading however, does two things: it also persists the WF state but also unloads it from memory; typically for a long running process.
Build the WF and run it. It’s ready to listen to requests on its endpoint.
Now run the client. Once the service sends the response back to the client (recall – no persistence on send here), it enters a delay shape for 1 minute. Meanwhile we have configured to persist the WF after 5 seconds. So wait 5 seconds and open table “InstancesTable”; just like in Part 1 you will see the WF state persisted:
However, now we have also configured the WF to unload after 20 seconds. So after an additional 15 seconds, this time open table “RunnableInstancesTable” and you will see one record corresponding to the same workflow. Why the “RunnableInstancesTable” table? Because this time the WF is not only persisted, but also is unloaded meaning that it is ready to be loaded again and continue execution:
After the delay shape finishes, the WF instance will be loaded again into memory and finishes execution. Both records will disappear from the database.
Finally, let’s add a control endpoint to our WF. Control endpoints allow sending commands to a WF instance from a client. Add the below code in the host application:
new WorkflowControlEndpoint(
new BasicHttpBinding(),
new EndpointAddress(new Uri(baseAddress) + “/wce”)
);
host.AddServiceEndpoint(controlEndpoint);
This code adds a special type of endpoint called the control endpoint with the following address: “http://localhost:8089/TestWF/wce”
Run the service and update the service reference at the client application. Add the below code at the client application just after invoking the service operation:
WorkflowControlEndpoint ep = new WorkflowControlEndpoint(new BasicHttpBinding(), new EndpointAddress(“http://localhost:8089/TestWF/wce”));
WorkflowControlClient client = new WorkflowControlClient(ep);
client.Terminate(workflowId);
This code creates a workflow control client and uses the workflow instance id to send a command to terminate the WF instance. To test this I have caused the thread to sleep for 30 seconds. This way I am sure that at this point the WF instance has been unloaded (review the WF configuration). Now when I send the Terminate command, notice how the WF instance does not continue execution and is terminated. To be sure, see how the database persistence records are deleted after just 30 seconds as opposed to the 1 minute as explained previously.