IBMMQDotnet client retry mechanism - c#

Hi everyone i am completely new to queues and especialy to IBMMQDotnet cleint library. Currently my application trying to send DTO object to the queue and sometimes it could faailed for various reasons like exception occuring or network issue. Is there any retrie mechanism ?i would like to implement retry mechansim, i tried to google it but could not found any example. Bellow is the current code
if (!TryConnectToQueueManager())
{
return;
}
using var destination = GetMqObjectForWrite(message.Destination, message.DestinationType);
var mqMessage = new MQMessage
{
Format = MQC.MQFMT_STRING,
CharacterSet = 1208
};
if (message.Headers?.Count > 0)
{
foreach (var (key, value) in message.Headers)
{
mqMessage.SetStringProperty(key, value);
}
}
mqMessage.WriteString(JsonSerializer.Serialize(message.Data));
destination.Put(mqMessage);
destination.Close();

IBM MQ provides a feature called as Client Auto Reconnect.You could refer the following KC page Client Auto Reconnect
If there is a connection failure because of the network issue, the IBM MQ client will try to re-establish a connection to the Queue Manager for a specific time period(which is configurable) before throwing an exception to the application
You could refer to the sample "SimpleClientAutoReconnectPut" & "SimpleClientAutoReconnectGet" which are available as part of the client installation.

Related

Can't connect to EventHubs with Kafka Client

I have an event hubs instance with a “test” eventhub.
I can connect to this and publish messages with the native client "Azure.Messaging.EventHubs"
However when I try to connect with the Confluent.Kafka (v1.1.0) client I get
“Unknown error (after 21286ms in state CONNECT)”
%3|1655301022.374|ERROR|rdkafka#producer-1|
[thrd:sasl_plaintext://my-event-hub-namespace.servicebus.windows.net:9093/bootstra]:
1/1 brokers are down
I'm setting the producer config, and creating producer as below
var config = new ProducerConfig
{
BootstrapServers = "my-eventhub-namespace.servicebus.windows.net:9093",
SecurityProtocol = SecurityProtocol.SaslSsl,
SaslMechanism = SaslMechanism.Plain,
SaslUsername = "$ConnectionString",
SaslPassword = "Endpoint=sb://my-eventhub-namespace.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=MySharedAccessKey==",
};
using (var producer = new ProducerBuilder<long, string>(config).SetKeySerializer(Serializers.Int64).SetValueSerializer(Serializers.Utf8).Build())
{
Any ideas as to where I'm going wrong?
Update :
When connecting with the native client it's connecting using WebSockets, so it's probably networking/firewall issue.
Thanks for your time.
A couple of things to try
Firewall check for EH endpoint. Make sure the client can connect to my-eventhub-namespace.servicebus.windows.net:9093.
Try with a namespace-level connection string if you used entity-level SAS.

Cannot connect to Azure ServiceBus with Microsoft.Azure.ServiceBus

I have created a very simple console application that connects to Azure ServiceBus and sends one message. I tried the latest library from Microsoft (Microsoft.Azure.ServiceBus) but no matter what I do I just get this error:
No connection could be made because the target machine actively
refused it ErrorCode: ConnectionRefused
I have tried exactly the same connection string in Service Bus Explorer and it does work just fine. Moreover I connected without problems using the older library from Microsoft (WindowsAzure.ServiceBus).
var sender = new MessageSender("endpoint", "topicName");
sender.SendAsync(new Message(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject("test"))));
I tried with .NET Framework 4.6.2 and Core, same exception. I suspect there may be some differences in the default protocol that these libraries use, but I could not figure out that for sure.
P.S. Have tried the example from Microsoft docs but result is still the same exception
The old client supported ConnectivityMode using TCP, HTTP, HTTPS, and AutoDetect. ServiceBus Explorer is using AutoDetect, trying TCP first and then failing over to HTTPS, regardless of the TransportMode you were using (SBMP or AMQP).
With the new client this has changed. TransportMode now combines both options and offers Amqp (AMQP over TCP) or AmqpWebSockets (AMQP over WebSockets). There's no AutoDetect mode. You will have to create your clients and specify TransportType as AmqpWebSockets to bypass blocked TCP port 5671 and instead use port 443.
It seems that the documentation is lacking a lot on how to connect using HTTPS (Amqp over WebSockets) but after some help from Sean Feldman in the accepted answer I managed to connect. Here is the code that I used if someone is interested:
var tokenProvider = TokenProvider.CreateSharedAccessSignatureTokenProvider(
"RootManageSharedAccessKey", // SharedAccessKeyName
"SomeToken");
var sender = new MessageSender(
"sb://mydomain.servicebus.windows.net/",
"topicName",
tokenProvider,
TransportType.AmqpWebSockets);
Or a variant that let's you have the whole connection string in one piece
var builder = new ServiceBusConnectionStringBuilder("YouConnectionString");
var tokenProvider = TokenProvider.CreateSharedAccessSignatureTokenProvider(
builder.SasKeyName,
builder.SasKey);
var sender = new MessageSender(
builder.Endpoint,
"TopicName",
tokenProvider,
TransportType.AmqpWebSockets);
It is actually possible to use ConnectionString directly but then it has to be augmented to use the right protocol.
var sender = new MessageSender("TransportType=AmqpWebSockets;Endpoint=...", "TopicName")
Or the version that allows to embed EntityPath into the ConnectionString
var connectionBuilder = new ServiceBusConnectionStringBuilder("EntityPath=MyTopic;TransportType=AmqpWebSockets;Endpoint=...")
var sender = new MessageSender(connectionBuilder);
I was having the same issue but his worked for me
var clientOptions = new ServiceBusClientOptions();
clientOptions.TransportType = ServiceBusTransportType.AmqpWebSockets;
client = new ServiceBusClient(connectionString, clientOptions);
sender = client.CreateSender(topicName);
// create a batch
using ServiceBusMessageBatch messageBatch = await sender.CreateMessageBatchAsync();

Azure and SignalR: System.Net.Sockets.SocketException: An attempt was made to access a socket in a way forbidden by its access permissions

I'm currently experiencing this issue at a high frequency:
System.Net.Sockets.SocketException: An attempt was made to access a
socket in a way forbidden by its access permissions
Sometimes it happens when connecting to Azure Storage from my web app (code below), but most of the time it happens with SignalR.
Based on debug diag, I see the following:
394 client connections in w3p.dmp have been executing a request for more than 90 seconds.
Based on the memory dump, there are a significant number of connections being made to /signalr/connect and /signalr/reconnect.
It looks like I'm using AspNet.SignalR.WebSockets.WebSocketHandler to make SignalR connections from within code. At this point I'm not sure what to look for though - what could be the culprit? We have a web service living in Azure, with web apps and mobile apps connecting to a SignalR backplane (redis).
Screen from debug diag
Code for Azure Storage
public void EnqueueRequest(int requestId)
{
// Retrieve storage account from connection string.
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(ConfigurationManager.AppSettings.Get("AzureStorageConnectionString"));
// Create the queue client.
CloudQueueClient queueClient = storageAccount.CreateCloudQueueClient();
// Retrieve a reference to a queue.
CloudQueue queue = queueClient.GetQueueReference(ConfigurationManager.AppSettings.Get("requestQueueName"));
// Create a message and add it to the queue.
CloudQueueMessage message = new CloudQueueMessage(castingCallId.ToString(CultureInfo.InvariantCulture));
queue.AddMessage(message);
}
Hub Proxy Code
var baseUrl = _dbContext.CurrentTenant.BaseUrl;
_hubConnection = new HubConnection(baseUrl);
_hubProxy = _hubConnection.CreateHubProxy("appHub");
await _hubConnection.Start();
string serialized = null;
try
{
serialized = JsonSerializerExtensions.SerializeObject(data).SanitizeData();
await _hubProxy.Invoke((isTypingNotification ? "SendTypingNotification" : "SendClientNotification"), serialized, username);
}
catch (Exception exception)
{
LogError("1: " + exception);
}
SB2055 and I worked on this and made the following changes to eliminate this issue:
Do not create a HubConnection for each message to send. A HubConnection is a heavyweight object and should be created once and reused. You can recreate the IHubProxy multiple times if needed. You can accomplish this by setting the HubConnection as a class static member variable.
We changed the connection type from web sockets to long polling.

Rabbitmq - Connecting to cluster from C#

We have created a RabbitMQ cluster with two nodes (rabbit and rabbit1). We have 4 queues which are configured to be highly available queues by following http://www.rabbitmq.com/clustering.html and http://www.rabbitmq.com/ha.html
Before clustering, we used to connect to the node using the snippet below.
var factory = new ConnectionFactory(){ HostName = _rabbitMQ_Hostname, UserName = _rabbitMQ_Username, Password = _rabbitMQ_Password};
using (var connection = factory.CreateConnection())
using (var channel = connection.CreateModel())
{
channel.QueueDeclare(queue: _autoCancellationPNS_QueueName,
durable: true,
exclusive: false,
autoDelete: false,
arguments: null);
string message = appointmentId.ToString();
var body = Encoding.UTF8.GetBytes(message);
IBasicProperties properties = channel.CreateBasicProperties();
properties.DeliveryMode = 2;
channel.BasicPublish(exchange: _rabbitMQ_Exchange,
routingKey: _autoCancellationPNS_RoutingKey,
basicProperties: properties,
body: body);
returnMessage.ShortMessage = "Added to queue";
returnMessage.LongMessage = "Added to queue";
logger.Debug("|Added to queue");
}
How should we deal with cluster?
The RabbitMQ.Client have been supporting connecting to multiple hosts for over a year. It was fixed in pull request #92. You should be able to do something like the following
using (var connection = connectionFactory.CreateConnection(hostList))
using (var channel = connection.CreateModel())
{
}
However, with this approach you would need to perform all the recovery etc. yourself. About a year ago, we had massive problem with stability in the EasyNetQ client, but since we started using RawRabbit our clustered environment and never really had a problem with it.
Disclaimer: I am the creator of RawRabbit.
You can connect to the node you prefer.
Exchanges and queues are visible across the cluster.
Using a load-balancer in front of the nodes is common practice, so the clients have to know only the balancer IP/DNS.
clients ----> balancer -----> RabbitMQ cluster
The .Net client does (to my knowledge) not offer any support for this. You build something yourself to select and connect to a node on the cluster.
For example, if you want to implement a round-robin strategy, the pseudo code would be something like
Get list of hostname/port combinations that form the cluster
do {
try {
connect to next hostname in the list
} catch (rabbit connection failed) {
maybe log a warning
}
} while not connected
Of course you now need to think about connection strategies, retries, number of connection attempts, exponential backoff, ...
... which is why I would strongly recommend to look for a library that already provides this kind of functionality (and much more). One such library is EasyNetQ (available on nuget), maybe NServiceBus (with RabbitMq Transport) or MassTransit could also be interesting.
Another approach could be to set up an intelligent loadbalancer in front of the individual nodes (so myrabbitcluster.mycompany.com load balances between the cluster nodes and should then be responsible to detect node failures and take faulty nodes out of the cluster).

SVN COPY error: 501 Method Not Implemented

We've been using VisualSVN (standard edition) for a few years without any problems. We have a C# application which stores data in SVN. It uses SharpSvn (https://sharpsvn.open.collab.net) library for SVN access. Occasionally, the application executes a server-side SVN COPY command (SharpSvn's "RemoteCopy") to create a branch based on a series of existing in the repository files.
We recently updated VisualSVN from version 2.5.2 to 3.2.2 and also purchased a license to unlock enterprise features of the product. We enabled Integrated Windows Authentication, but also kept Basic Authentication for backward compatibility.
After running for a week without any problems (performing only reads from SVN), our application tried to perform the copy for the first time, and it failed with the following error complaining about one of the files that had to be copied:
"COPY request on '/svn/repository/!svn/rvr/12345/trunk/file.xml' failed: 501 Method Not Implemented"
The server log reveals the following:
Level,Date and Time,Source,Event ID,Task Category
Error,2015-03-03 9:37:26 AM,VisualSVN Server 3.2,1001,Apache,"Multi-author commits not supported. [501, #175002] [client 192.168.1.100]"
Error,2015-03-03 9:37:26 AM,VisualSVN Server 3.2,1001,Apache,"Could not fetch resource information. [501, #0] [client 192.168.1.100]"
Error,2015-03-03 9:37:26 AM,VisualSVN Server 3.2,1001,Apache,"SSPI Challenge failed: The token supplied to the function is invalid [client 192.168.1.100]"
Error,2015-03-03 9:37:21 AM,VisualSVN Server 3.2,1001,Apache,"SSPI Challenge failed: The token supplied to the function is invalid [client 192.168.1.100]"
After restarting VisualSVN service, the command completed without any problems. This had never happened before with the older versions of VisualSVN.
This is how we create a branch using SharpSvn:
private static void Branch(ICollection<SvnUriTarget> sources, Uri targetUri, string comment, string userName, string password)
{
if (sources == null) throw new ArgumentNullException("sources");
if (targetUri == null) throw new ArgumentNullException("targetUri");
if (comment.IsNullEmptyOrSpaces()) throw new ArgumentNullException("comment");
if (userName.IsNullEmptyOrSpaces()) throw new ArgumentNullException("userName");
if (password.IsNullEmptyOrSpaces()) throw new ArgumentNullException("password");
using (var client = new SvnClient())
{
client.Authentication.Clear();
client.Authentication.DefaultCredentials = new NetworkCredential(userName, password);
client.Authentication.SslServerTrustHandlers += (sender, e) => { e.AcceptedFailures = e.Failures; e.Save = true; };
SvnCommitResult commitResult;
if (!client.RemoteCopy(sources, targetUri, new SvnCopyArgs { CreateParents = true, LogMessage = comment }, out commitResult))
throw new ApplicationException("Failed to create tag/branch in Repository");
}
}
In our application, we are still using Basic Authentication, and credentials are explicitly passed to every SharpSvn call. The application requests credentials from the user, and then it uses these credentials to perform a single call of the "Branch" method.
Two different users tried to do this using their own credentials on two different machine with the same result. Only restart of VisualSVN service fixed the problem. I'm worried that this problem may come back again...
You should disable SharpSvn (and Subversion) to use Integrated Authentication ('ntlm' and 'negotiate') if you're going to specify credentials for operation.
Try add code like this:
client.Configuration.SetOption("servers", "global", "http-auth-types", "basic");
Probably this is a bug in Subversion, SharpSvn or serf, but proposed workaround should work.

Categories