Executing workflow under distributed transaction
-
Wednesday, June 27, 2007 7:00 AM
Hi, I know that in Framework 3.0 it was not possible to execute workflow under distributed transaction that flows in from web service call(The workflow runtime will always create local transaction).
Is this fixed in Orcas and Framework 3.5. I want to create wcf services that have methods implemented as simple workflows without tracing and persistence, and I want to execute that short running workflow under the same distributed transaction that was received through service call from client.
Thanks,
Indigo Cowboy
Answers
-
Thursday, July 19, 2007 3:50 PM
You can interact with transaction in WF in three ways:
- TransactionScopeActivity to coordinate work within and stemming from a workflow.
- A work item or custom service that implements IPendingWork will receive notification when a persistence commit occurs. For example when enqueuing a message to an instance you can provide an object that implements IPendingWork. When the next persistence point occurs that IPendingWork will get a call to Commit with the persistence transaction.
- You can flow a transaction into a workflow when calling WorkflowInstance.Unload. This allows the following pattern:
- Create a System.Transaction.TransactionScope in your host code
- Do some transaction aware work (for example dequeue a row from a database work queue).
- Deliver a message to a workflow.
- Call WorkflowInstance.Suspend
- Call WorkflowInstance.Unload
- Commit the TransactionScope
- Call WorkflowInstance.Resume
In this example the persistence point that occurs as part of the Unload in [5] will be transactionally consistent with the work done in [2].
Thanks,
Joel
All Replies
-
Wednesday, June 27, 2007 6:56 PM
Hi,
In .Net Framework 3.5 wcf and wf integration is rather easy. Here is what your "simple workflows as methods" will be like:
Lets say you have a fast food service, your operations will be take order, process order, deliver order. How you will implement these operations is in the following case:
Workflow1
ReceiveActivity1 for TakeOrder
ReceiveActivity2 for ProcessOrder
ReceiveActivity3 for DeliverOrder
The receive activity that comes out of the box in 3.5 is a composite activity in which you can have simple workflows in, i.e.:
ReceiveActivity2 for ProcessOrder
Put fries in the fryer,
Put buns on the pan
Put meat on the pan
Put soda in the glass
Get the fries out....etc etc etc
On the client side you can have a Workflow or a regular WCF client. In workflow case you have SendActivity which is a non-composite activity that sends the message, you have before send and after response handlers to perform operations before the message is sent and after the reply is received (in two-way operation case)
I hope this is what you were looking for,
Thanks
Elif
-
Friday, June 29, 2007 7:03 AM
This doesn't work. I created simple workflow that has one Receive activity, and Service contract set to Mandatory for transactions and binding also set enable transaction flow. I called the service from client transaction scope and checked that inside workflow Transaction.Current is null.
Can someone help me with this?
Thanks,
Indigo Cowboy
-
Friday, June 29, 2007 3:02 PM
- try to use ManualWorkflowSchedulerService
Thanks
Roman
-
Friday, June 29, 2007 4:39 PM
Roman - how would this help?
AFAIK they have not changed the Workflow implementation in Orcas to allow transactions to flow into any workflows or any events exception WorkflowUnloaded. Someone from MS could speak up though if I am incorrect.
-
Friday, June 29, 2007 6:29 PM
Jon,
You are right, my answer was not correct, in the Orcas/B1 is not that change.
The ambient transaction context is suppressed by WorkflowExecutor, therefore any scheduler will not help here.
Code Snippet from the WorkflowExecutor.RunSome methodusing (TransactionScope scope = new TransactionScope(TransactionScopeOption.Suppress))
{
try
{
this.FireWorkflowExecutionEvent(this, WorkflowEventInternal.Executing);
this.RunScheduler();
}
catch (Exception exception)
{
...
throw;
}
finally
{
.... }
scope.Complete();
}Thanks
Roman
-
Sunday, July 01, 2007 6:17 AM
Thanks friends on your responses. I first tried with manuallworkflowschedulerservice because I wanted to execute short running wf (withot persistence and tracking) synch on the running thread. When this failed I tried to do the same thing using receive activity without success. From Romans code it is obvious that is still not fixed.
I remember that when I visited MS last year they told us that this will be supported in next version of wf. My team released maybe the first live product on wf for Loan Origination in the early 2006, and I want to use expirience and know how on new product that we are building, beside I like WF(and WCF) a lot
I am pretty sure that short running workflow with simple activities can be easily executed under distributed transactions in sceanarios without persistence and tracking services. Without this functionality we can not use wf in new product. MS can support distributed transactions flow in in this simple scenario.
Can someone from MS help us with this problem, and tell us will this and when be fixed?
Thanks to whole community on this and all previous answers, you helped me always to step forward when i was without idea and solution. The battle between man and computer continues

Indigo Cowboy
-
Tuesday, July 03, 2007 2:23 AMIt is not currently possible to flow in transactions. We are looking into being able to do this for the next version of WF. For clarification the upcoming changes that will be in the Orcas timeframe are not considered the next version.
-
Friday, July 06, 2007 9:46 AMProbably it is possible to propagate distributed transaction on workflow instance by calling DependentClone(DependentCloneOption.BlockCommitUntilComplete) method on current transaction and passing DependentTransaction as parameter to workflow instance.
-
Wednesday, July 18, 2007 12:34 PM
I tried to create custom DistributedTransactionScopeActivity that is complex activity that when executes sets Transaction.Current. When you call
WorkflowInstance instance = Program.Runtime.CreateWorkflow(typeof(FTPService.ProvideAccountTransfer));
instance.Start();
ManualWorkflowSchedulerService schedulerService = Program.Runtime.GetService<ManualWorkflowSchedulerService>();
bool result = schedulerService.RunWorkflow(instance.InstanceId);
under Distributed Transaction workflow runtime removes transaction and code activity in workflow will execute with Transaction.Current = null. Custom activity that I created only sets Transaction.Current with Transaction value that is received in wcf service call. Code activities that are inside custom activity execute with Transaction.Current set in custom activity. The problem occurs when scheduler service is finished with workflow execution. Transaction.Current is Aborted, and wcf client that called service under transaction throws exception. It looks like wf runtime aborts distributed transaction. I tried with dependent transaction but wf runtime aborts it also.Does enyone has idea?
Thanks,
Indigo Cowboy
-
Wednesday, July 18, 2007 4:36 PM
I strongly recommend that you do not smuggle transactions into a WF workflow. This is unsupported. The transactional semantics of the workflow will not behave correctly in regards to your external transaction. You might be able to get this to look like it is working correctly some of the time with some fiddling but you will get inconsistent results, especially in failure cases which is just when you need consistency the most (meaning that you won't get the ACID semantics that you are after, at least in regards to persistence of the workflow instance and the work contained in the transaction you brought in).
Thanks,
Joel
-
Thursday, July 19, 2007 6:16 AM
Joel thanks on your answer.
Is there any other way to support transactions, maybe to write custom scheduler service or something?
If this is not possible I will end up writting custom workflow runtime (I think that I do not have time for this) or i will give it up from WF.
Thanks,
Indigo Cowboy
-
Thursday, July 19, 2007 3:50 PM
You can interact with transaction in WF in three ways:
- TransactionScopeActivity to coordinate work within and stemming from a workflow.
- A work item or custom service that implements IPendingWork will receive notification when a persistence commit occurs. For example when enqueuing a message to an instance you can provide an object that implements IPendingWork. When the next persistence point occurs that IPendingWork will get a call to Commit with the persistence transaction.
- You can flow a transaction into a workflow when calling WorkflowInstance.Unload. This allows the following pattern:
- Create a System.Transaction.TransactionScope in your host code
- Do some transaction aware work (for example dequeue a row from a database work queue).
- Deliver a message to a workflow.
- Call WorkflowInstance.Suspend
- Call WorkflowInstance.Unload
- Commit the TransactionScope
- Call WorkflowInstance.Resume
In this example the persistence point that occurs as part of the Unload in [5] will be transactionally consistent with the work done in [2].
Thanks,
Joel
-
Friday, July 20, 2007 1:12 PM
Joel thanks on your help. I tried the third way. I created transaction scope in host(i tried also to use transaction that flows in from wcf service method), I used my custom activity to set Transaction.Current inside workflow. But because I use manual workflow scheduler in order to execute workflow i execute workflow on the same thread that comes from wcf method call I can not call Workflow instance.Suspend from host.
WorkflowInstance instance = Program.Runtime.CreateWorkflow(typeof(FTPService.ProvideAccountTransfer)); ManualWorkflowSchedulerService schedulerService = Program.Runtime.GetService<ManualWorkflowSchedulerService>();instance.Start();
bool result = schedulerService.RunWorkflow(instance.InstanceId);//I have to wait for wf to finish workflow, but then the transaction is aborted
I tried to add Suspend activity in workflow, and it returns controll to host but Transaction is aborted. I can do this if I use two threads, one to call manualworkflowscheduler.run and the second one that will call suspend. I am not sure will this help because I think that the suspend activity does the sam thing?
If I add delay activity i will receive activity i will get WorkflowIdled event, but the transaction is aborted. It happens also on workflowSuspended event. It looks like that workflow aborts transaction always when it returns execution to host.
If I understood well step [3] from your example will be
WorkflowInstance instance = Program.Runtime.CreateWorkflow(typeof(FTPService.ProvideAccountTransfer));
ManualWorkflowSchedulerService schedulerService = Program.Runtime.GetService<ManualWorkflowSchedulerService>();
instance.Start();
bool result = schedulerService.RunWorkflow(instance.InstanceId);
?
Maybe you thought to use DefaultWorkflowScheduler?
I can send you my sample, or if you have sample can you send me?
Thanks,
Indigo Cowboy
-
Friday, July 20, 2007 4:00 PM
Apologies if I wasn't clear - you can't actually flow in a transaction in such a way that your activity will execute under it. In the third case the transaction only flows in for the Unload call and coordinates workbatch commit data (such as persistence or any custom service that implements IPendingWork).
Thanks,
Joel
-
Friday, July 20, 2007 6:03 PM
Our recent project required that all workflow operations be transactional, including the activities executed within the workflows. This is what is required to accomplish this:
1) Use ManualWorkflowSchedulerService
2) By default WF does not flow in ambient transactions, so a custom TransactionService (a double dictionary keyed by thread and instanceID) must be used. Set the Transaction.Current in the service for the current thread before invoking an event on the workflow.
3) Exceptions do not flow out of the WF runtime, so a custom exception service is required (very similar to the transaction service) to re-throw exceptions after an event is raised on the workflow.
4) The default SqlWorkflowPersistenceService must be customized (Reflector works good) to set 'Enlist=true' (this is required for loading workflow instance so it is part of the same transaction to prevent deadlocks)
5) Create a base activity that all activities should derive from. This simply creates a TransactionScope (using the transaction stored in the TransactionService for the thread and instance) and calls the derived class's 'DoExecute' method.
6) Instance.Unload must occur after firing an event and within the same TransactionScopeIf any exception occurs during an Activity's Execute method, the transaction is rolled back and the State Machine is returned to it's original state. This setup will allow any number of events to be invoked on any number of Workflow Instances within the same transaction. A transaction is only valid on the thread it was created (at least the way we built it).
Even though the workflow is long running (many years), the time span from one Event handler to the next, must be less than the transaction timeout. Obviously this is a significant constraint if your workflow has many complex activities between EventHandlers. In general, workflows are mostly waiting for input from external actors and the activities themselves should execute in a reasonable timeframe. If you cannot get the activity sequence to execute in the allotted transaction time period, then it is recommended that you wrap your Raise event with a TransactionScope that explicitly un-enlists from the transaction and use compensation instead.
Another Caveat: The default TransactionScopeActivity will stop working correctly. This could be overcome be creating a custom TransactionScopeActivity or by further modification to the custom SqlWorkflowPersistenceService.
-
Tuesday, July 24, 2007 1:39 PM
Hi Murk. Thanks on your idea, but it looks like that it can be used in scenario where you need PersistenceService. Because I do not use persistence it looks like that
CommitWorkBatch method on custom WorkflowCommitWorkBatch service does not execute.
In my case I do not need persistence and tracking, I want to create short running transacted workflows.
I think that I found the way to solve this. I posted detailed description here:
Can someone check my solution for this problem and confirm me that from his point of view it is ok, and does he/she sees some potential problem with this solution?
I tested the solution and it works fine, but maybe there is something that I overlooked?
Thanks,
Indigo Cowboy
-
Monday, August 06, 2007 12:28 PM
I posted sample of DistributedTransactionScope(DTSA) activity on
http://dynamicsyu.com/blogs/indigocowboy/attachment/1.ashx
under post
Please review my solution for transaction flow inside workflow, and tell me what do you think about it?
Thanks, Indigo Cowboy
-
Friday, October 19, 2007 2:35 AM
Murk,
I just posted a recent thread on a very similar topic. Some quick questions:
1. Can your solution flow in a transaction across multiple workflow instances?
2. Who is calling Instance.Unload?
3. Where are you setting Transaction.Current prior to invoking an event on the workflow.
Your help is greatly appreciated.
-
Thursday, October 23, 2008 11:11 AM
I am hosting a state machine workflow from within a WCF service.
I have created a WCF service. In the WCF service operation I have started a state machine workflow synchronously (using ManualSchedularService). The workflow runtime is associated with the SqlWorkflowPersistenceService.
Once the workflow completes it execution in current state, it does not change the state and becomes idled. Hence, it returns to the Service operation. Thereafater, I want to serialize my business enitity data as well as workflow into a single transaction.
How can I ensure that if my business logic to store the entity data fails, then the workflow should also get roll backed?
To implement this, I have created TransactionScope inside the Service Operation itself. I do not want the service to accept transaction from client application. Hence I have not applied any Transaction attributes to the Service Contract and implementation class.
(Note: Even if I specify those attributes, it doesn’t make any difference to the result that I am getting right now.)
The result I am getting right now is that is the entity is not saved, and then still the workflow gets saved into the database.
Below is the code that I have written in my WCF Service operation.
public void ProcessContent(string content)
{
using (TransactionScope scope = new TransactionScope())
{
try
{
// I want to ensure that if my business logic to store the entity data fails, then the workflow should also be not persisted.
ProcessContent("test"); //Method to start a workflow.
//Based on the workflow processing I want to update business entity
using (SqlConnection connection = new SqlConnection("Password=patni;User ID=sa;Initial Catalog=new_snowleopard;Data Source=localhost;Packet Size=4096;"))
{
connection.Open();
using (SqlCommand cmd = connection.CreateCommand())
{
cmd.CommandText = "Insert into test(id,name) values(1,'foo')";
cmd.ExecuteNonQuery();
}
}
scope.Complete();
}
catch (Exception ex) { }
}
}
Please help me.
-
Thursday, October 23, 2008 11:12 AM
I am hosting a workflow from within a WCF service.
I have created a WCF service. In the WCF service operation I have started a state machine workflow synchronously (using ManualSchedularService). The workflow runtime is associated with the SqlWorkflowPersistenceService.
Once the workflow completes it execution in current state, it does not change the state and becomes idled. Hence, it returns to the Service operation. Thereafater, I want to serialize my business enitity data as well as workflow into a single transaction.
How can I ensure that if my business logic to store the entity data fails, then the workflow should also get roll backed?
To implement this, I have created TransactionScope inside the Service Operation itself. I do not want the service to accept transaction from client application. Hence I have not applied any Transaction attributes to the Service Contract and implementation class.
(Note: Even if I specify those attributes, it doesn’t make any difference to the result that I am getting right now.)
The result I am getting right now is that is the entity is not saved, and then still the workflow gets saved into the database.
Below is the code that I have written in my WCF Service operation.
public void ProcessContent(string content)
{
using (TransactionScope scope = new TransactionScope())
{
try
{
// I want to ensure that if my business logic to store the entity data fails, then the workflow should also be not persisted.
ProcessContent("test"); //Method to start a workflow.
//Based on the workflow processing I want to update business entity
using (SqlConnection connection = new SqlConnection("Password=patni;User ID=sa;Initial Catalog=new_snowleopard;Data Source=localhost;Packet Size=4096;"))
{
connection.Open();
using (SqlCommand cmd = connection.CreateCommand())
{
cmd.CommandText = "Insert into test(id,name) values(1,'foo')";
cmd.ExecuteNonQuery();
}
}
scope.Complete();
}
catch (Exception ex) { }
}
}
Please help me.
-
Monday, September 21, 2009 12:54 PMHello,
I am currently working on framework 4.0 version. It just a few months I have been introduced to the workflows and newbie to this world.
I have read this entire thread and want to understand about how I could define a transaction in the workflow activity. The solution like using Scheduler service and all...I am somehow confused with them. Is it possible to write these things with 4.0 version bcz somewhere I read that this refers to 3.5 WF version. Do correct me if I am assuming anything wrong here.
Your suggestions can put me forward in this issue. Bcz currently I am nowhere in knowing abt how I can define a transaction scope inside workflow activity. One more point to add is I want to use sqlpersistence service since my workflows are complex and definitely need this service to be active.
I want to define the transaction scope inside the Workflow activities Execute () method so inside this if anything goes wrong all my changes should be rolled back.
Thanks -
Monday, March 22, 2010 10:54 AM
Hellp IndigoCowboy, the page http://dynamicsyu.com/blogs/indigocowboy/archive/2007/07/25/supporting-distributed-transactions-in-wf.aspx is not availble.
Can you help me ?
Thanks