Reading/Writing a websphere queue from an Async method - c#

I have a asynchronous method that is responsible for only connecting to the queue and reading from the queue. While trying to read I get an error from the WebSphere dll 'amqmdnet.dll' that says "Thread was being aborted". I get this error every time I try to modify the queue in any way, and only when I try to modify from an asynchronous method. I've also tried implementing the IBM.XMS.net dll as this was said to be used for asynchronous messaging, although I get the same error. Is it possible to read a queue from inside an async method? If so, is the implementation for reading/writing different for synchronous and asynchronous when it comes to modifying the queue itself? I can connect to the queue manager just fine, its modifying the queue that's giving me issues.
Main:
private async Task ReadAsync()
{
await MqMessanger.ConnectAsync(); // connects fine
await MqMessanger.StartReadingAsync(); // errors out
}
MqMessanger: (IBM.XMS.net dll)
private XMSFactoryFactory factoryFactory; //used for connection
private IConnectionFactory cf; //used for connection
private ISession sessionWMQ;
private IDestination destination;
private IMessageConsumer consumerAsync;
private MessageListener messageListener;
public IConnection QueueManager { get; set; }
//QueueManager has been connected prior to this
private void StartReadingAsync()
{
try
{
//Creates a session where an Ack is sent to the server to delete the message as soon the message is received.
sessionWMQ = QueueManager.CreateSession(false, AcknowledgeMode.AutoAcknowledge);
destination = sessionWMQ.CreateQueue(queueName);
// Create consumer object to read messages from the queue
consumerAsync = sessionWMQ.CreateConsumer(destination);
// Create a message listener to fire when a message is put on the queue and assign it to consumer
messageListener = new MessageListener(OnMessageCallback);
consumerAsync.MessageListener = messageListener;
}
catch (Exception ex)
{
throw new Exception($"Error reading from '{destination.Name}'.", ex);
}
}
MqMessanger: (amqmdnet dll)
//QueueManager has been connected prior to this
private void StartReadingAsync()
{
try
{
queue = queueManager.AccessQueue(queueName, MQC.MQOO_INPUT_AS_Q_DEF + MQC.MQOO_FAIL_IF_QUIESCING);
queueMessage = new MQMessage();
queueMessage.Format = MQC.MQFMT_STRING;
queueGetMessageOptions = new MQGetMessageOptions();
queue.Get(queueMessage, queueGetMessageOptions);
string message = queueMessage.ReadString(queueMessage.MessageLength);
//Do something with this message
}
catch (Exception ex)
{
throw new Exception($"Error reading from '{destination.Name}'.", ex);
}

I think there is some confusion here between Asynchronous messaging pattern of IBM MQ and Asynchronous programming concept of .NET Framework.
IBM MQ enables application to application connectivity in an asynchronous way through queuing. In a typical client-server pattern, both client and server applications need to be up and running always for data exchange. This is synchronous pattern. In asynchronous pattern, client application and server application are not required to be running always. Client can send a message to MQ and go away. The message will be residing in a MQ queue. If the server application is running, that message will be delivered to server application. The server will process that message and put a reply message into MQ queue and go away. The client application can come back after some time and read the reply message. As you can see client and server applications are not simultaneously but still they are able to communicate in a asynchronous way via MQ.
I am not an expert in the newer .NET Framework concepts. The async programming concept in .NET Framework is for offloading short tasks that can be independently by the CPU without blocking a thread. For example when the main thread is busy displaying contents of a web page, the job of connecting to a database could be offloaded to a .NET task so that the user is able to interact with the web page.
IBM MQ .NET (amqmdnet and XMS) use multiple threads for communicating with a queue manager. I am unsure if 'async' programming technique is suitable when multiple threads are involved. This could be the reason for "Thread was being aborted" error.

Related

Different threads try to handle the same TCP socket: can this cause instability?

I'm working on a C# Docker application, where I am creating a microservice in order to handle TCP socket communication. This works, but it seems to be very unstable (some packets pass, some not). I have added a log entry, which might explain something (it's about sending a message over a TCP socket):
Source code (shown on multiple lines, but it's a oneliner):
Debug.WriteLine(
$"T[{System.Threading.Thread.CurrentThread.ManagedThreadId}],
{DateTime.UtcNow}: Handle().
Trying to send [{Message}] to [{ConnectionName}]");
Results:
T[14], 12/14/2022 15:26:08: Handle(). Trying to send [abc] to [XL_Test]
T[19], 12/14/2022 15:26:32: Handle(). Trying to send [abc] to [XL_Test]
As you can see, apparently my application always uses another thread to handle the requests. So, I'm left with a very simple question: is multithreaded programming allowed when working with TCP sockets?
For your information: I have already worked with multithreaded applications on TCP sockets before, where one thread was used for regular checking the connection and another for sending the messages, but here I have one thread which regularly checks the connection, while for sending messages, always another thread gets opened.
Edit: I don't know if this is helpful, but the name of the thread, handling the message, is .Net ThreadPool Worker.
Edit2: this is the way this Send() method is called:
await _mediator.Send(command);
... where _mediator is an IMediator from the MediatR library.
The first comment refers to another StackOverflow post which is using locks, but while trying this, I got a compilation error:
object lockobject = new object();
lock(lockobject)
{
await _mediator.Send(command);
}
The compiler message is CS1996: Cannot await in the body of a lock statement. (Pardon my ignorance, but I'm very new at this)

Check if Rabbit MQ is down

I am writing a C# Console app (Windows scheduled task) to monitor the status of Rabbit MQ. So in case the the queue is down (service down, connection timeout, or any other reason) it will send a notification mail. I have used RabbitMQ .Net client (version 4.1.1). Basically I am checking if the CreateConnection() is successfull.
private static void CheckRabbitMQStatus()
{
ConnectionFactory factory = new ConnectionFactory();
factory.Uri = "amqp://guest:guest#testserver:5672/";
IConnection conn = null;
try
{
conn = factory.CreateConnection();
conn.Close();
conn.Dispose();
}
catch (Exception ex)
{
if (ex.Message == "None of the specified endpoints were reachable")
{
//send mail MQ is down
}
}
}
Is this the right approach to achieve this? There are several tools and plugins available for Rabbit MQ but I want a simple solution in C#.
It should work, if you have a simple message queue setup (without clustering or federation of multiple machines).
The RabbitMQ API has an aliveness check, designed for use by monitoring tools such as yours. It actually sends and receives a message. This is likely to be a more sensitive health check than yours. See the last item on here.
https://www.rabbitmq.com/monitoring.html#health-checks
RabbitMQ itself is robust. Usually the failure mode it experiences is its host being rebooted for other reasons.
Note: There's a nice DebuggableService template by Rob Three in the Windows Marketplace. This makes it pretty easy to rig your health check as a service rather than as a scheduled task. My life got easier when I refactored my MQ stuff to run as services rather than scheduled tasks.

Azure Service Bus integration with SignalR

This question is not about Scaleout with SignalR and Azure Service Bus. I want to build a Service Bus listener (e.g. OnMessage) into my SignalR web socket app that then distributes the message accordingly to connected users. Messages will be posted from various separately running services into the centralized Service Bus and the UI/browser connected to the web socket servers should receive these.
Option 1: I can add an async Task into a hub method to subscribe to a Service Bus and filter by the connected user. The problem with this is it uses an extra thread from the thread pool and will do this for every socket connection the user has started. Our app can easily start 5-10 or more sockets for every tab open.
Option 2: I can add a single task to the SignalR Startup.Configuration method that then receives all messages and distributes them to the proper connected users. The problem I've encountered here is that I don't have access to the Clients object used for sending to the browser.
I feel like SignalR and Service Bus are a good complement to each other to enable near real-time communications but I can find very little to implement a scenario like this. And I feel like this should be a common enough scenario. Perhaps I'm missing some obvious design patterns that would be a better solution.
I was able to figure this out. In the SignalR Startup.Configuration method I added a method to start the listener and in that method I called GlobalHost.ConnectionManager.GetHubContext. Currently this doesn't send to individual users but I'll add a connection manager of some sort to handle that.
public void startServiceBusListener()
{
// setup subcsription
var namespaceManager = NamespaceManager.CreateFromConnectionString(connectionString);
if (!namespaceManager.SubscriptionExists("myTopic", Environment.MachineName))
namespaceManager.CreateSubscription("myTopic", Environment.MachineName);
SubscriptionClient busClient = SubscriptionClient.CreateFromConnectionString(connectionString, "myTopic", Environment.MachineName);
// Configure the callback options.
OnMessageOptions options = new OnMessageOptions();
options.AutoComplete = false;
options.AutoRenewTimeout = TimeSpan.FromMinutes(1);
receiveTask = Task.Run(() =>
{
// handle new messages
busClient.OnMessage((message) =>
{
try
{
Notification note = message.GetBody<Notification>();
string notification = JsonConvert.SerializeObject(note);
GlobalHost.ConnectionManager.GetHubContext<DispatchHub>().Clients.All.notify(notification);
// Remove message from subscription.
message.Complete();
}
catch (Exception)
{
// Indicates a problem, unlock message in subscription.
message.Abandon();
}
}, options);
}, cts.Token);
}

C# Listener Making IBM MQ Message Cleared Automatically

I have a C# listener for IBM MQ like below. Only listener method mentioned here.
private void OnMessage(IMessage msg)
{
try
{
ITextMessage textMsg = (ITextMessage)msg;
Console.Write("Got a message: ");
Console.WriteLine(textMsg.Text);
}
catch(Exception ex)
{
}
}
Whenever a text format message has been reached in side my queue, above listener is invoking and i am able to read values.
Problem is that if you stop the listener and then push a message, that
message is retaining in MQ Explorer. But if the listener method has been invoked, the
message has been deleting from "Web Sphere MQ Explorer" always just after
read from the listener method. Do I need to set some more
configuration to retain my messages even after my listener read it?
There are 2 ways to read messages from a queue:
destructive get (default)
using a non-destructive get (aka browse)
If you want to only browse messages in a queue then use the non-destructive get.
That is the expected behavior. The message in a queue is being consumed by an application (meaning your OnMessage method). WebSphere MQ will deliver the message to a waiting consumer application as soon as the message arrives in queue.
If you want to messages to remain in the queue, then you need to stop all your consumer application.

Implementing client callback functionality in WCF

The project I'm working on is a client-server application with all services written in WCF and the client in WPF. There are cases where the server needs to push information to the client. I initially though about using WCF Duplex Services, but after doing some research online, I figured a lot of people are avoiding it for many reasons.
The next thing I thought about was having the client create a host connection, so that the server could use that to make a service call to the client. The problem however, is that the application is deployed over the internet, so that approach requires configuring the firewall to allow incoming traffic and since most of the users are regular users, that might also require configuring the router to allow port forwarding, which again is a hassle for the user.
My third option is that in the client, spawns a background thread which makes a call to the GetNotifications() method on server. This method on the server side then, blocks until an actual notification is created, then the thread is notified (using an AutoResetEvent object maybe?) and the information gets sent to the client. The idea is something like this:
Client
private void InitializeListener()
{
Task.Factory.StartNew(() =>
{
while (true)
{
var notification = server.GetNotifications();
// Display the notification.
}
}, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default);
}
Server
public NotificationObject GetNotifications()
{
while (true)
{
notificationEvent.WaitOne();
return someNotificationObject;
}
}
private void NotificationCreated()
{
// Inform the client of this event.
notificationEvent.Set();
}
In this case, NotificationCreated() is a callback method called when the server needs to send information to the client.
What do you think about this approach? Is this scalable at all?
For each client you are going to hold a thread on the server. If you have a few hundred clients and the server wouldn't use the memory anyway, that may be fine. If there can be more clients, or you do not wish to burn 1MB of stack per client, you should make some changes:
Use an async WCF action method. They allow you to unblock the request thread while the method is waiting.
Change the event model to an async once. SemaphoreSlim has async support. You can also use TaskCompletionSource.
That way you can scale up to many connections.

Categories

Resources