问题
I'm sure I'm not the first to say it, but there's a severe lack of documentation on the finer points of Service Bus 1.0 for Windows Server out there... I'm hoping some of the MS insiders can help clear a few things up...
Do services utilizing queues/topics run in an implicit, ambient transaction? For instance consider the following code snippet:
[ServiceBehavior] public class MySbService : IDoWork { [OperationBehavior] void DoSomeWork(WorkRequest request) { DoDatabaseWork(); DoMoreDatabaseWork(); } }
In the above sample, without creating an explicit
TransactionScope
, wouldDoDatabaseWork()
be committed ifDoMoreDatabaseWork()
throws an exception? In other words, does the queued operation run under an ambient transaction tracked by MSDTC?Do Service Bus 1.0 queues automatically retry if an exception is thrown (like MSMQ does)? I ask because I haven't come across any
.config
setting for thenetMessagingBinding
that specifies retry behavior. Also when creating queues usingService Bus Explorer
the closest thing I see isMaxDeliveryAttempt
. Coming from an MSMQ background, I'm used to seeing exception messages appear in the retry/poison queues. Is there something synomomous with this in the Service Bus 1.0 world?
Thank you in advance
UPDATE:
Please see my answer below for more details. I am modifying this question to ask the following:
Is it possible using contract-first, IIS-hosted, WCF with Service Bus 1.0 to 'cover' client sending to the service bus in a transaction? If so, how? Also, what is the mechanism that is used?
回答1:
I believe I've found the answer to both of my questions...
For
Transactional
operations, i don't believe there is an "ambient" transaction. I've proven this by simply throwing an exception after a database operation, and sure enough, the data is committed anyway. I would like to know if there's a preferred method of declaring transaction scope, i.e.:[OperationBehavior(TransactionScopeRequired = true)] public void MyServiceOperation(){ ... } //or using the TransactionScope public void MyServiceOperation() { using(var transScope = new TransactionScope(...)){ ... } }
For retry functionality, it looks like you need to enable the
ReceiveContext
, following this blog:[ServiceContract] public interface IMyService { [OperationContract(IsOneWay=true)] [ReceiveContextEnabled(ManualControl = true)] void MyServiceOperation(); // and in the service implementation: [OperationBehavior] public void MyServiceOperation() { var incomingProperties = OperationContext.Current.IncomingMessageProperties; var property = incomingProperties[BrokeredMessageProperty.Name] as BrokeredMessageProperty; //Complete the Message ReceiveContext receiveContext; if (ReceiveContext.TryGet(incomingProperties, out receiveContext)) { //Do Something receiveContext.Complete(TimeSpan.FromSeconds(10.0d)); } else { throw new InvalidOperationException("..."); } }
UPDATE:
After digging a little deeper, I've found that the OperationContext` completion isn't really an option if you're using plain vanilla, contract-first, IIS-hosted, WCF with Service Bus 1.0 (not sure why, but I'm hoping someone could shed some light on this)
What I have found is about the only sane option for transactional behavior is the following:
[OperationBehavior]
public void MyServiceOperation()
{
using(var transScope = new TransactionScope(...))
{
DbWork();
transScope.Complete();
}
Client.SendToServiceBus(); // <-- Cannot be part of transaction, otherwise
// exceptions will be thrown!
}
The problem remains that this pattern, unlike say MSMQ, does not allow for the entire operation to be rolled-back if sending the message to the service bus fails. (unless of course, someone out there knows better...)
This also means you're forced to roll-your-own retry logic and likely some mechanism to verify at the next step that the previous step was committed. YUCK!
From what I understand, Workflow Services and dealing directly with brokered messages gives you some out-of-the-box retry capabilities. But if you're IIS-hosting your Workflow Services with IIS via AppFabric, then somehow Microsoft figured out how to get the transaction to cover sending to the Service Bus. (If anyone knows what that mechanism is, please let me know!)
回答2:
For #2, you can get retries through Transient Fault Handling Framework
http://windowsazurecat.com/2011/02/transient-fault-handling-framework/
Read through this document for usage related to the Service Bus.
http://social.technet.microsoft.com/wiki/contents/articles/best-practices-for-leveraging-windows-azure-service-bus-brokered-messaging.aspx?Sort=MostRecent&PageIndex=1
来源:https://stackoverflow.com/questions/15509955/service-bus-1-0-for-windows-server-transaction-error-handling