how to detect connection issues to rabbit mq using mass transit? - c#

how to detect if the message broker configuration is valid or if the connection to the message broker is lost using Mass Transit to RabbitMQ? When publishing messages when RabbitMQ is present does not seems to complain if there is no broker connection right away and seems to recover when the RabbitMQ server comes up. Is there a way to listen in on the connection events and warn if the configuration is not valid?

If you use .NET Core and configure MassTransit as per the docs, you can resolve the instance of IBusHealth and use it in your service.
The AddMassTransit method registers the default instance, which you can ask for the bus health status at any time. That's the method code:
public HealthResult CheckHealth()
{
var endpointHealthResult = _endpointHealth.CheckHealth();
var data = new Dictionary<string, object> {["Endpoints"] = endpointHealthResult.Data};
return _healthy && endpointHealthResult.Status == BusHealthStatus.Healthy
? HealthResult.Healthy("Ready", data)
: HealthResult.Unhealthy($"Not ready: {_failureMessage}", data: data);
}
As you can see, if you call busHealth.CheckHealth() it will return either Healthy or Unhealthy and in the latter case would also give you the list of failing endpoints.
Since BusHealth only monitors the bus itself and all its receive endpoints, you might not get notified when your service failed to publish messages.
You can use the diagnostics listener or create your own publish or send observer, which is called before and after publish/send and on any failure.

Related

Order of messages in Azure Service Bus

My Azure Service Bus has only one topic and there is only one publisher. The publisher sends messages to the topic with this code:
public void Publish<T>(T messageObject)
{
var jsonString = JsonSerializer.Serialize(messageObject);
var message = new ServiceBusMessage(jsonString);
message.ApplicationProperties["messageType"] = typeof(T).Name;
serviceBusSender.SendMessageAsync(message);
}
In my application code, I call this method consecutively to send message1, message2 and message3, respectivly. However, when I go to Azure, and receive messages on Service Bus Explorer, I see the messages' order is not necessarily the same.
Is this behavior expected? Or am I missing something here?
If you have created the non-partitioned entity then you can enable the Support ordering feature as documented here.
The Support ordering feature allows you to specify whether messages
that are sent to a topic will be forwarded to the subscription in the
same order in which they were sent. This feature doesn't support
partitioned topics. For more information, see
TopicProperties.SupportOrdering in .NET or
TopicProperties.setOrderingSupported in Java.
In case of partitioned entity your can leverage the session while sending the message. A session will give you related messages in the exact arrival order if you process them in sequence, meaning using one thread and without prefetching. When the consumer fails processing a message and abandons it, that message will again be the first to be delivered until it exceeds its delivery count.

Setting TTL on RabbitMQ queue using Servicestack

I have read that it is possible to set a time to live (TTL) on a RabbitMQ (per queue) so that a message will be wiped from the queue by the RabbitMQ server if the TTL expires, and that the server will guarantee that messages that have an expired TTL will not be processed.
I am using service stack to connect to various rabbitMq's; specifically I am using it to act as a facade over the RPC functionality rabbitMQ provides, and it does work quite well.
I am unable to find any information (and also looking at the code - support) for setting the queue's TTL when it is declared. As far as I can see, the creation of the queue is buried in the Service Stack implementation - which abstracts a lot of the queue details to provide a simplified service abstraction regardless of the transport layer.
Is it possible to do this (to set a TTL on the rabbit MQ using service stack) - or will it be possible to do this in the future?
I've added a filter which will let you customize what options Rabbit MQ Queue's and topics get created with which you can specify with the new CreateQueueFilter, e.g:
container.Register<IMessageService>(c =>
new RabbitMqServer(ConnectionString)
{
CreateQueueFilter = (queueName, args) =>
{
if (queueName == QueueNames<MyRequest>.In)
{
args["x-message-ttl"] = 60000;
}
}
});
This change is available from v4.5.7+ that's now available on MyGet.

Azure Servicebus multiple unknown consumers

I need to create a queue from which multiple unknown subscribers can get messages.
Each subscriber should only receive each message once and will mark the message complete/abandon but only for themselves. The message would remain on the queue for other subscribers.
Reading the documentation suggests that i need to create a topic and then multiple subscriptions. However, due to architectural reasons. i can't specify in advance what the subscribers are going to be. I want it to be possible for new subscribers to start consuming the messages without having to change my queue config.
Can azure servicebus handle this scenario? Also some of the subscribers will be using the rest client and not the .net client.
Thanks
Not necessarily a complete answer to this, but yes it’s possible to make Service Bus work in this way providing you stay within the Azure service quota limits.
A client can create its own subscription
string connectionString = CloudConfigurationManager.GetSetting("ServiceBus.ConnectionString");
// Note issue of how you secure this if necessary
var namespaceManager = NamespaceManager.CreateFromConnectionString(connectionString);
if (!namespaceManager.SubscriptionExists(TOPIC_NAME, SUBSCRIPTION_NAME))
{
//var messagesFilter = new SqlFilter("you can add a client filter for the subscription");
SubscriptionDescription sd = new SubscriptionDescription(TOPIC_NAME, SUBSCRIPTION_NAME)
{
// configure settings or accept the defaults
DefaultMessageTimeToLive = TimeSpan.FromDays(14),
EnableDeadLetteringOnMessageExpiration = true,
MaxDeliveryCount = 1000,
LockDuration = TimeSpan.FromMinutes(3)
};
namespaceManager.CreateSubscription(sd);
// or namespaceManager.CreateSubscription(sd, messagesFilter);
}
// subscription client for the new topic
_subscriptionClient = SubscriptionClient.CreateFromConnectionString(connectionString, TOPIC_NAME, SUBSCRIPTION_NAME, ReceiveMode.PeekLock);
There is an equivalent in the Rest api
https://msdn.microsoft.com/en-us/library/azure/hh780748.aspx
Once the subscription is created the client will be able to receive its own copy of any messages sent to the topic from that point on.
You don’t say how many clients but you will need to stay within the Service Bus service limitations
https://azure.microsoft.com/en-us/documentation/articles/service-bus-quotas/
However, you don’t include any information about your application and what the nature of the clients is and there could be many reasons that this is not an advisable solution. Including
Clients will need knowledge of the subscription security keys.
Uncoordinated clients will have to create unique subscription names.
The clients can delete subscriptions when they are finished with them but are you able to ensure that occurs?
Depending on configuration a number of inactive clients could cause your topic to reach its quota limit and stop accepting new messages.
… and probably a lot more
If the clients are not under your control I would say this is definitely not the right solution.

Azure service bus paired namespace - simulate failover

I am working with azure service bus paired namespace and need to be able to simulate a failover to the secondary namespace. I did kind of have this working by entering an incorrect connection string for the primary namespace and saw it fail over and send the message to the secondary namespace. This no longer seems to do the trick. I can not find a way through the azure management portal or anywhere else to take a namespace offline. Anyone any ideas how to do this?
Here is my code for reference
var pairedNamespaceConfiguration = this.pairedNamespaceConfigurationDictionary[configurationKey];
MessagingFactory factory = MessagingFactory.CreateFromConnectionString(pairedNamespaceConfiguration.PrimaryNamespace.ConnectionString);
MessagingFactory secondaryMessagingFactory = MessagingFactory.CreateFromConnectionString(pairedNamespaceConfiguration.SecondaryNamespace.ConnectionString);
NamespaceManager secondaryNamespaceManager = NamespaceManager.CreateFromConnectionString(pairedNamespaceConfiguration.SecondaryNamespace.ConnectionString);
SendAvailabilityPairedNamespaceOptions sendAvailabilityOptions = new SendAvailabilityPairedNamespaceOptions(secondaryNamespaceManager, secondaryMessagingFactory, pairedNamespaceConfiguration.BacklogQueueCount, TimeSpan.FromSeconds(pairedNamespaceConfiguration.FailoverIntervalSeconds), false);
factory.PairNamespaceAsync(sendAvailabilityOptions).Wait();
MessageSender messageSender = factory.CreateMessageSender(pairedNamespaceConfiguration.PathName);
string messageContent = JsonConvert.SerializeObject(message);
using(BrokeredMessage brokeredMessage = new BrokeredMessage(messageContent))
{
messageSender.Send(brokeredMessage);
}
Modify your \Windows\system32\drivers\etc\hosts file to point the original namespace to something like 127.0.0.1. This will make the original namespace connection fail.
I'm using this example Geo-replication with Service Bus Relayed Messages to implement the same think. Maybe it's useful for you also.
All Service Bus entities reside in a namespace. A namespace is affiliated to a datacenter. To allow for a failover between datacenters, the user must create one Service Bus and ACS namespace (in case ACS is used) per datacenter. Any Service Bus relay that needs to remain accessible in the presence of datacenter failures must be created in both namespaces.
The server opens two NetTcp relay endpoints, one in each of the two namespaces. The server processes any request that is received via one of these endpoints. Note that the two relays have to have different names (.e.g, address of primary relay is sb://myPrimaryNamespace.servicebus.windows.net/myService-primary and b://mySecondaryNamespace.servicebus.windows.net/myService-secondary).
The client considers one of the two replicated relays as the active relay and the other one as a backup. It opens a channel to the active relay and invokes methods on the service. If the invocation fails with any exception that is not part of the service contract, the client abandons the channel, opens a channel to the backup relay, and invokes the service method again. The client will consider the new channel to be the active channel and continues to use that channel until the next fault occurs.

SignalR scaleout client to server broadcast

Using SignalR scaleout how can I broadcast the message from client to all the servers attached to my backplane? I thought it should work by default, however only one server's hub is receiving the message.
Setup: I have 4 virtual machines behind the load balancer and I am using SignalR with Redis backplane. I have the following Hub:
public class ProgressHub : Hub
{
public void StartProcessing(string clientId)
{
// ...
}
}
And on the client side, I am invoking this method with:
$.connection.hub.start().done(function() {
proghub.server.startProcessing(me.clientId);
});
I've enabled tracing on the Message bus and the message is received on all the servers:
SignalR.ScaleoutMessageBus Information: 0 : OnReceived(0, 54, 1)
However, the Hub method is invoked on only one server. How can I make this call execute the StartProcessing method on all servers?
It is not possible. The best way is to enable some kind of synchronization mechanism between servers. Since Redis is used as a backplane it can be also used as such mechanism.

Categories