Rebus Send in transactionscope - servicebus

It was possible in previous (<=0.84.0) versions of Rebus to Send message in TransactionScope and it was sent only if scope is completed
using (var scope = new TransactionScope())
{
var ctx = new AmbientTransactionContext();
sender.Send(recipient.InputQueue, msg, ctx);
scope.Complete();
}
Is it possible to achive the same behaviour in Rebus2

As you have correctly discovered, Rebus version >= 0.90.0 does not automatically enlist in ambient transactions.
(UPDATE: as of 0.99.16, the desired behavior can be had - see the end of this answer for details on how)
However this does not mean that Rebus cannot enlist in a transaction - it just uses its own ambient transaction mechanism (which does not depend on System.Transactions and will be available when Rebus is ported to .NET core).
You can use Rebus' DefaultTransactionContext and "make it ambient" with this AmbientRebusTransactionContext:
/// <summary>
/// Rebus ambient transaction scope helper
/// </summary>
public class AmbientRebusTransactionContext : IDisposable
{
readonly DefaultTransactionContext _transactionContext = new DefaultTransactionContext();
public AmbientRebusTransactionContext()
{
if (AmbientTransactionContext.Current != null)
{
throw new InvalidOperationException("Cannot start a Rebus transaction because one was already active!");
}
AmbientTransactionContext.Current = _transactionContext;
}
public Task Complete()
{
return _transactionContext.Complete();
}
public void Dispose()
{
AmbientTransactionContext.Current = null;
}
}
which you can then use like this:
using(var tx = new AmbientRebusTransactionContext())
{
await bus.Send(new Message());
await tx.Complete();
}
or, if you're using it in a web application, I suggest you wrap it in an OWIN middleware like this:
app.Use(async (context, next) =>
{
using (var transactionContext = new AmbientRebusTransactionContext())
{
await next();
await transactionContext.Complete();
}
});
UPDATE: Since Rebus 0.99.16, the following has been supported (via the Rebus.TransactionScope package):
using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
scope.EnlistRebus(); //< enlist Rebus in ambient .NET tx
await _bus.SendLocal("hallÄ i stuen!1");
scope.Complete();
}

Related

NServiceBus with RabbitMQ Simple event

I want to be able to used NServiceBus to add a message on a queue in RabbitMQ. I dont want to handle it yet so just want to see an item on the queue, my code is as follows, but I get this error when I run it?
I have been trying to look at the documentation but is seems overly confusing. I am familar with RabbitMq and using it as is or with the Rabbit client library, but NService bus seems to complicate and confuse the situation!
using Shared;
using System;
using System.Threading.Tasks;
namespace NServiceBus.RabbitMqTest
{
class Program
{
static async Task Main(string[] args)
{
var endpointConfiguration = new EndpointConfiguration("UserChanged");
var transport = endpointConfiguration.UseTransport<RabbitMQTransport>();
transport.UseConventionalRoutingTopology();
transport.ConnectionString("host=localhost;username=guest;password=guest");
//transport.Routing().RouteToEndpoint(typeof(MyCommand), "Samples.RabbitMQ.SimpleReceiver");
endpointConfiguration.EnableInstallers();
var endpointInstance = await Endpoint.Start(endpointConfiguration).ConfigureAwait(false);
await SendMessages(endpointInstance);
//await endpointInstance.Publish(new UserChanged { UserId = 76 });
await endpointInstance.Stop().ConfigureAwait(false);
}
static async Task SendMessages(IMessageSession messageSession)
{
Console.WriteLine("Press [e] to publish an event. Press [Esc] to exit.");
while (true)
{
var input = Console.ReadKey();
Console.WriteLine();
switch (input.Key)
{
//case ConsoleKey.C:
// await messageSession.Send(new MyCommand());
// break;
case ConsoleKey.E:
await messageSession.Publish(new UserChanged { UserId = 87 });
break;
case ConsoleKey.Escape:
return;
}
}
}
}
}
Your endpoint is publishing the message as well as receiving it. Since there's no handler defined to handle the UserChanged messages (events), NServiceBus recoverability kicks in. Your options are
Declare the endpoint as send-only to avoid handling the messages when there are no handlers defined
Define a handler for UserChanged

NServiceBus Send-Only endpoints not generating heartbeats

I'm using NServiceBus.Core v6.4.3 and NServiceBus.Heartbeat v2.0.0
I have a console application running as a Scheduled Task, it extracts data and send commands to an endpoint for processing.
The console application is configured as a SendOnly endpoint.
My code is as follows:
Main
// Local NServiceBus Configuration
var endpointConfiguration = EndpointConfiguration();
// Global NServiceBus & Ninject configuration
var conventions = new NServiceBusConventions();
conventions.Customize(endpointConfiguration);
// Create and start endpoint
var endpointInstance = await Endpoint.Start(endpointConfiguration).ConfigureAwait(false);
EndpointConfiguration
private static EndpointConfiguration EndpointConfiguration()
{
var configuration = new EndpointConfiguration("EndpointName");
// To ensure OctopusDeploy doesn't cause ServicePulse to think multiple services have been deployed
// http://docs.particular.net/nservicebus/hosting/override-hostid
configuration.UniquelyIdentifyRunningInstance()
.UsingNames("EndpointName", Environment.MachineName);
configuration.SendOnly();
return configuration;
}
Conventions
public class NServiceBusConventions
{
public IKernel Kernel;
public void Customize(EndpointConfiguration configuration)
{
// Custom Logging Factory implementation
LogManager.UseFactory(new NServiceBusTraceLoggerFactory());
Kernel = NinjectCommon.Start();
configuration.UseContainer<NinjectBuilder>(b => b.ExistingKernel(Kernel));
configuration.UsePersistence<NHibernatePersistence>();
configuration.UseSerialization<JsonSerializer>();
configuration.UseTransport<MsmqTransport>();
var transport = configuration.UseTransport<MsmqTransport>();
// Enabled by default in MsmqTransport, but to ensure we have it
transport.Transactions(TransportTransactionMode.TransactionScope);
configuration.DefineCriticalErrorAction(NServiceBusOnCriticalError.OnCriticalError);
configuration.EnableInstallers();
configuration.Conventions()
.DefiningCommandsAs(t => t.Namespace != null && t.Namespace.Equals("Contracts.Commands"))
.DefiningEventsAs(t => t.Namespace != null && t.Namespace.Equals("Contracts.Interfaces.Events"));
configuration.AuditProcessedMessagesTo(ConfigurationManager.AppSettings["Messaging.NServiceBus.QueueNames.AuditQueue"]);
configuration.SendFailedMessagesTo(ConfigurationManager.AppSettings["Messaging.NServiceBus.QueueNames.ErrorQueue"]);
configuration.SendHeartbeatTo(ConfigurationManager.AppSettings["Messaging.NServiceBus.QueueNames.ServiceControlQueue"]);
var scanner = configuration.AssemblyScanner();
var excludeRegexs = new List<string>
{
#"DevExpress.*\.dll"
};
var baseDirectory = AppDomain.CurrentDomain.BaseDirectory;
foreach (var fileName in Directory.EnumerateFiles(baseDirectory, "*.dll").Select(Path.GetFileName))
{
foreach (var pattern in excludeRegexs)
{
if (Regex.IsMatch(fileName, pattern, RegexOptions.IgnoreCase))
{
scanner.ExcludeAssemblies(fileName);
break;
}
}
}
}
}
Removing the configuration.SendOnly(); line in EndpointConfiguration makes the endpoint appear in ServicePulse, but it doesn't appear otherwise.
I knew this was an issue in previous versions, but I thought this had been fixed in NServiceBus V5.
I don't have to configure the endpoint as Send-Only, but I was just for completeness.
The reason behind the missing heartbeats was:
I have a console application running as a Scheduled Task, it extracts
data and send commands to an endpoint for processing.
The process would start fresh each time and the time taken to extract data, process and send the commands was too short for NServiceBus to get the heartbeat messages sent.
Putting an await Task.Delay(10000) at the end of the application was enough to allow NServiceBus to complete its necessary bootstrapping and didn't impact our SLA.
Thanks to Sean Farmar for his help in diagnosing

Callback is not invoked on the client

I have a self-hosted service that processes long running jobs submitted by a client over net.tcp binding. While the job is running (within a Task), the service will push status updates to the client via a one-way callback. This works fine, however when I attempt to invoke another callback to notify the client the job has completed (also one-way), the callback is never received/invoked on the client. I do not receive any exceptions in this process.
My Callback contract looks like this:
public interface IWorkflowCallback
{
[OperationContract(IsOneWay = true)]
[ApplySharedTypeResolverAttribute]
void UpdateStatus(WorkflowJobStatusUpdate StatusUpdate);
[OperationContract(IsOneWay = true)]
[ApplySharedTypeResolverAttribute]
void NotifyJobCompleted(WorkflowJobCompletionNotice Notice);
}
Code from the service that invokes the callbacks: (not in the service implementation itself, but called directly from the service implementation)
public WorkflowJobTicket AddToQueue(WorkflowJobRequest Request)
{
if (this.workflowEngine.WorkerPoolFull)
{
throw new QueueFullException();
}
var user = ServiceUserManager.CurrentUser;
var context = OperationContext.Current;
var workerId = this.workflowEngine.RunWorkflowJob(user, Request, new Object[]{new DialogServiceExtension(context)});
var workerjob = this.workflowEngine.FindJob(workerId);
var ticket = new WorkflowJobTicket()
{
JobRequestId = Request.JobRequestId,
JobTicketId = workerId
};
user.RegisterTicket<IWorkflowCallback>(ticket);
workerjob.WorkflowJobCompleted += this.NotifyJobComplete;
workerjob.Status.PropertyChanged += this.NotifyJobStatusUpdate;
this.notifyQueueChanged();
return ticket;
}
protected void NotifyJobStatusUpdate(object sender, PropertyChangedEventArgs e)
{
var user = ServiceUserManager.GetInstance().GetUserWithTicket((sender as WorkflowJobStatus).JobId);
Action<IWorkflowCallback> action = (callback) =>
{
ICommunicationObject communicationCallback = (ICommunicationObject)callback;
if (communicationCallback.State == CommunicationState.Opened)
{
try
{
var updates = (sender as WorkflowJobStatus).GetUpdates();
callback.UpdateStatus(updates);
}
catch (Exception)
{
communicationCallback.Abort();
}
}
};
user.Invoke<IWorkflowCallback>(action);
}
protected void NotifyJobComplete(WorkflowJob job, EventArgs e)
{
var user = ServiceUserManager.GetInstance().GetUserWithTicket(job.JobId);
Action<IWorkflowCallback> action = (callback) =>
{
ICommunicationObject communicationCallback = (ICommunicationObject)callback;
if (communicationCallback.State == CommunicationState.Opened)
{
try
{
var notice = new WorkflowJobCompletionNotice()
{
Ticket = user.GetTicket(job.JobId),
RuntimeOptions = job.RuntimeOptions
};
callback.NotifyJobCompleted(notice);
}
catch (Exception)
{
communicationCallback.Abort();
}
}
};
user.Invoke<IWorkflowCallback>(action);
}
In the user.Invoke<IWorkflowCallback>(action) method, the Action is passed an instance of the callback channel via OperationContext.GetCallbackChannel<IWorkflowCallback>().
I can see that the task that invokes the job completion notice is executed by the the service, yet I do not receive the call on the client end. Further, the update callback is able to be invoked successfully after a completion notice is sent, so it does not appear that the channel is quietly faulting.
Any idea why, out of these two callbacks that are implemented almost identically, only one works?
Thanks in advance for any insight.

WCF ChannelFactory and channels - caching, reusing, closing and recovery

I have the following planned architecture for my WCF client library:
using ChannelFactory instead of svcutil generated proxies because
I need more control and also I want to keep the client in a separate
assembly and avoid regenerating when my WCF service changes
need to apply a behavior with a message inspector to my WCF
endpoint, so each channel is able to send its
own authentication token
my client library will be used from a MVC front-end, so I'll have to think about possible threading issues
I'm using .NET 4.5 (maybe it has some helpers or new approaches to implement WCF clients in some better way?)
I have read many articles about various separate bits but I'm still confused about how to put it all together the right way. I have the following questions:
as I understand, it is recommended to cache ChannelFactory in a static variable and then get channels out of it, right?
is endpoint behavior specific to the entire ChannelFactory or I can apply my authentication behavior for each channel separately? If the behavior is specific to the entire factory, this means that I cannot keep any state information in my endpoint behavior objects because the same auth token will get reused for every channel, but obviously I want each channel to have its own auth token for the current user. This means, that I'll have to calculate the token inside of my endpoint behavior (I can keep it in HttpContext, and my message inspector behavior will just add it to the outgoing messages).
my client class is disposable (implements IDispose). How do I dispose the channel correctly, knowing that it might be in any possible state (not opened, opened, failed ...)? Do I just dispose it? Do I abort it and then dispose? Do I close it (but it might be not opened yet at all) and then dispose?
what do I do if I get some fault when working with the channel? Is only the channel broken or entire ChannelFactory is broken?
I guess, a line of code speaks more than a thousand words, so here is my idea in code form. I have marked all my questions above with "???" in the code.
public class MyServiceClient : IDisposable
{
// channel factory cache
private static ChannelFactory<IMyService> _factory;
private static object _lock = new object();
private IMyService _client = null;
private bool _isDisposed = false;
/// <summary>
/// Creates a channel for the service
/// </summary>
public MyServiceClient()
{
lock (_lock)
{
if (_factory == null)
{
// ... set up custom bindings here and get some config values
var endpoint = new EndpointAddress(myServiceUrl);
_factory = new ChannelFactory<IMyService>(binding, endpoint);
// ???? do I add my auth behavior for entire ChannelFactory
// or I can apply it for individual channels when I create them?
}
}
_client = _factory.CreateChannel();
}
public string MyMethod()
{
RequireClientInWorkingState();
try
{
return _client.MyMethod();
}
catch
{
RecoverFromChannelFailure();
throw;
}
}
private void RequireClientInWorkingState()
{
if (_isDisposed)
throw new InvalidOperationException("This client was disposed. Create a new one.");
// ??? is it enough to check for CommunicationState.Opened && Created?
if (state != CommunicationState.Created && state != CommunicationState.Opened)
throw new InvalidOperationException("The client channel is not ready to work. Create a new one.");
}
private void RecoverFromChannelFailure()
{
// ??? is it the best way to check if there was a problem with the channel?
if (((IChannel)_client).State != CommunicationState.Opened)
{
// ??? is it safe to call Abort? won't it throw?
((IChannel)_client).Abort();
}
// ??? and what about ChannelFactory?
// will it still be able to create channels or it also might be broken and must be thrown away?
// In that case, how do I clean up ChannelFactory correctly before creating a new one?
}
#region IDisposable
public void Dispose()
{
// ??? is it how to free the channel correctly?
// I've heard, broken channels might throw when closing
// ??? what if it is not opened yet?
// ??? what if it is in fault state?
try
{
((IChannel)_client).Close();
}
catch
{
((IChannel)_client).Abort();
}
((IDisposable)_client).Dispose();
_client = null;
_isDisposed = true;
}
#endregion
}
I guess better late then never... and looks like author has it working, this might help future WCF users.
1) ChannelFactory arranges the channel which includes all behaviors for the channel. Creating the channel via CreateChannel method "activates" the channel. Channel factories can be cached.
2) You shape the channel factory with bindings and behaviors. This shape is shared with everyone who creates this channel. As you noted in your comment you can attach message inspectors but more common case is to use Header to send custom state information to the service. You can attach headers via OperationContext.Current
using (var op = new OperationContextScope((IContextChannel)proxy))
{
var header = new MessageHeader<string>("Some State");
var hout = header.GetUntypedHeader("message", "urn:someNamespace");
OperationContext.Current.OutgoingMessageHeaders.Add(hout);
}
3) This is my general way of disposing the client channel and factory (this method is part of my ProxyBase class)
public virtual void Dispose()
{
CloseChannel();
CloseFactory();
}
protected void CloseChannel()
{
if (((IChannel)_client).State == CommunicationState.Opened)
{
try
{
((IChannel)_client).Close();
}
catch (TimeoutException /* timeout */)
{
// Handle the timeout exception
((IChannel)innerChannel).Abort();
}
catch (CommunicationException /* communicationException */)
{
// Handle the communication exception
((IChannel)_client).Abort();
}
}
}
protected void CloseFactory()
{
if (Factory.State == CommunicationState.Opened)
{
try
{
Factory.Close();
}
catch (TimeoutException /* timeout */)
{
// Handle the timeout exception
Factory.Abort();
}
catch (CommunicationException /* communicationException */)
{
// Handle the communication exception
Factory.Abort();
}
}
}
4) WCF will fault the channel not the factory. You can implement a re-connect logic but that would require that you create and derive your clients from some custom ProxyBase e.g.
protected I Channel
{
get
{
lock (_channelLock)
{
if (! object.Equals(innerChannel, default(I)))
{
ICommunicationObject channelObject = innerChannel as ICommunicationObject;
if ((channelObject.State == CommunicationState.Faulted) || (channelObject.State == CommunicationState.Closed))
{
// Channel is faulted or closing for some reason, attempt to recreate channel
innerChannel = default(I);
}
}
if (object.Equals(innerChannel, default(I)))
{
Debug.Assert(Factory != null);
innerChannel = Factory.CreateChannel();
((ICommunicationObject)innerChannel).Faulted += new EventHandler(Channel_Faulted);
}
}
return innerChannel;
}
}
5) Do not re-use channels. Open, do something, close is the normal usage pattern.
6) Create common proxy base class and derive all your clients from it. This can be helpful, like re-connecting, using pre-invoke/post invoke logic, consuming events from factory (e.g. Faulted, Opening)
7) Create your own CustomChannelFactory this gives you further control how factory behaves e.g. Set default timeouts, enforce various binding settings (MaxMessageSizes) etc.
public static void SetTimeouts(Binding binding, TimeSpan? timeout = null, TimeSpan? debugTimeout = null)
{
if (timeout == null)
{
timeout = new TimeSpan(0, 0, 1, 0);
}
if (debugTimeout == null)
{
debugTimeout = new TimeSpan(0, 0, 10, 0);
}
if (Debugger.IsAttached)
{
binding.ReceiveTimeout = debugTimeout.Value;
binding.SendTimeout = debugTimeout.Value;
}
else
{
binding.ReceiveTimeout = timeout.Value;
binding.SendTimeout = timeout.Value;
}
}

Do WCF support Asynchronously operations' invoke within TransactionScope?

I am trying out the WCF Transaction implementation and I come up with the idea that whether asynchronous transaction is supported by WCF 4.0.
for example,
I have several service operations with client\service transaction enabled, in the client side, I use a TransactionScope and within the transaction, I create Tasks to asynchronously call those operations.
In this situation, I am assuming that the transaction is going to work correctly, is that right?
I doubt that very much. It appears that you if you are starting an ascync operation you are no longer participating on the original transaction.
I wrote a little LINQPad test
void Main()
{
using (var scope = new TransactionScope(TransactionScopeOption.Required))
{
try
{
Transaction.Current.Dump("created");
Task.Factory.StartNew(Test);
scope.Complete();
}
catch (Exception e)
{
Console.WriteLine(e);
}
Thread.Sleep(1000);
}
Console.WriteLine("closed");
Thread.Sleep(5000);
}
public void Test()
{
using (var scope = new TransactionScope(TransactionScopeOption.Required))
{
Transaction.Current.Dump("test start"); // null
Thread.Sleep(5000);
Console.WriteLine("done");
Transaction.Current.Dump("test end"); // null
}
}
You'll need to set both the OperationContext and Transaction.Current in the created Task.
More specifically, in the service you'll need to do like this:
public Task ServiceMethod() {
OperationContext context = OperationContext.Current;
Transaction transaction = Transaction.Current;
return Task.Factory.StartNew(() => {
OperationContext.Current = context;
Transaction.Current = transaction;
// your code, doing awesome stuff
}
}
This gets repetitive as you might suspect, so I'd recommend writing a helper for it.