Consumer service not dequeuing all messages from ActiveMQ queue - c#

I have a windows service that is attempting to consume messages from some activemq queue's. However, it is only getting some of the messages and others are getting stuck in 'messages pending' in the queue. ActiveMQ tells me it has enqueued lets say 500 messages to the consumer but only 300 were dequeued. There is more than one listener being set up in the service. Here's the important part of the code:
private void setupListener(string queue, string brokerUri)
{
try
{
ISession session = connectionConsumers[brokerUri].CreateSession();
session.CreateConsumer(session.GetQueue(queue))
.Listener += new MessageListener(consumer_Listener);
}
catch (Exception ex)
{
Log.Error("An exception has occured setting up listener for " + queue + " on " + brokerUri + ": {0}, {1}", ex, ex.Message);
}
}
void consumer_Listener(IMessage message)
{
try
{
processLog((message as ITextMessage).Text);
message.Acknowledge();
}
catch (NMSException ex)
{
Log.Error("ActiveMQ Connection Failure: {0}, {1}", ex, ex.Message);
}
catch (Exception ex)
{
Log.Error("An exception has occured trying to process a message: {0}, {1}", ex, ex.Message);
}
}
Is there something wrong with the way I'm acknowledging messages that would cause certain ones to not be acknowledged? Is it a concurrency issue? I'm not sure if they are all still going through the processLog function (added to my database).
EDIT: I think it has more to do with acknowledgements not happening properly (for some reason). I am not getting exceptions thrown in my logs. However, activemq shows the following:
From what I've read, the dispatch queue is being filled with messages that were sent to the consumer but not acknowledged. Why could this be?

The problem had to do with our queues being virtual destinations.

Related

How to programmatically retrieve reason code from a XMS XMSException

I have a XMS MQ Client app that is pulling off messages from a series of MQ endpoints. There are certain reason codes for which the process can continue, and for some that it should abort. For example a MQRC_Q_MGR_NOT_AVAILABLE 2059 for one endpoint shouldn't abort the whole process. Consequently I would like to check for this reason code.
cf = factoryFactory.CreateConnectionFactory();
foreach (Endpoint e in env.GetEndpoints())
{
Console.WriteLine("Consuming messages from endpoint {0}({1})", e.host, e.port);
// Set the properties
SetConnectionProperties(cf, e);
try
{
ReceiveMessagesFromEndpoint(cf);
}
catch (XMSException ex)
{
Console.WriteLine("XMSException caught: {0}", ex);
Console.WriteLine("Error Code: {0}", ex.ErrorCode);
Console.WriteLine("Error Message: {0}", ex.Message);
}
}
Problem is that the only attributes available on the XMSException to examine are ex.ErrorCode and ex.Message, which are respectively:
Error Code: CWSMQ0006
and
Error Message: CWSMQ0006E: An exception was received during the call to the method ConnectionFactory.CreateConnection: CompCode: 2, Reason: 2059.
I can see the Reason in the Message, but can't find a method or attribute to retrieve it.
There are probably 2 ways to do it
1) You can use the LinkedException
Something like the following
try
{
}
catch (XMSException e)
{
if(e.LinkedException!=null)
Console.WriteLine(e.LinkedException.Message);
else
Console.WriteLine(e);
}
2) Reference amqmdnet.dll as well to the project and use MQException.Something like
try
{
}
catch (XMSException e)
{
if(e.LinkedException!=null)
{
IBM.WMQ.MQException inner = (IBM.WMQ.MQException)e.LinkedException;
Console.WriteLine("Reason:"+ inner.ReasonCode);
}
else
Console.WriteLine(e);
}
Solution by OP
Based on accepted answer, a 'working' code is:
cf = factoryFactory.CreateConnectionFactory();
foreach (Endpoint e in env.GetEndpoints())
{
Console.WriteLine("Consuming messages from endpoint {0}({1})", e.host, e.port);
// Set the properties
SetConnectionProperties(cf, e);
try
{
ReceiveMessagesFromEndpoint(cf);
}
catch (XMSException ex)
{
Console.WriteLine("XMSException caught: {0}", ex);
Console.WriteLine("Error Code: {0}", ex.ErrorCode);
Console.WriteLine("Error Message: {0}", ex.Message);
if (ex.LinkedException != null &&
IBM.XMS.MQC.MQRC_Q_MGR_NOT_AVAILABLE.ToString().Equals(ex.LinkedException.Message))
{
Console.WriteLine("Queue Manager on this endpoint is not available");
Console.WriteLine("Moving onto next endpoint");
continue;
}
Console.WriteLine("Unexpected Error - Aborting");
throw;
}
}

Kill Process on failed restart

I'm quite new to C# and i'm having trouble with a program i'm writing.
I'm trying to create a service that monitors another service, the service i'm monitoring is notoriously unreliable and falls over constantly. Since it's written in a different language and the person who wrote it is long gone, our only options is to use a separate program to make sure its up and responding.
I've written a service that sends a message to the service, and if it gets a response, doesn't do anything, if it doesn't get a response, it initiates the restart. This essentially attempts to STOP the service, then start it again when it's done, or in case of it not responding to this, kills the process entirely.
it seems to work most of the time, but I've been having trouble with process kill. In the log i'm getting the error
System.ComponentModel.Win32Exception: An instance of the service is already running
Which tells me that the process kill is not kicking in when the service is not responding to the stop.
Can someone please tell me what i'm doing wrong here?
public static void Restart(string serviceName, int timeoutMilliseconds,bool debug)
{
ServiceController service = new ServiceController(serviceName);
try
{
int millisec1 = Environment.TickCount;
TimeSpan timeout = TimeSpan.FromMilliseconds(timeoutMilliseconds);
if ((service.Status.Equals(ServiceControllerStatus.Running)) || (service.Status.Equals(ServiceControllerStatus.StartPending)))
{
service.Stop();
service.WaitForStatus(ServiceControllerStatus.Stopped, timeout);
}
// count the rest of the timeout
int millisec2 = Environment.TickCount;
timeout = TimeSpan.FromMilliseconds(timeoutMilliseconds - (millisec2 - millisec1));
// if STILL running, hard kill the process
if ((service.Status.Equals(ServiceControllerStatus.Running)) || (service.Status.Equals(ServiceControllerStatus.StartPending)))
{
Library.WriteErrorLog("Service not responding to STOP command, killing process: " + serviceName);
foreach (var process in Process.GetProcessesByName(serviceName))
{
try
{
process.Kill();
}
catch (Exception ex)
{
Library.WriteErrorLog("Process Kill failed: " + ex.ToString());
}
}
}
service.Start();
service.WaitForStatus(ServiceControllerStatus.Running, timeout);
}
catch (System.ServiceProcess.TimeoutException ex)
{
if (debug)
{
Library.WriteErrorLog("Restart Timed out: " + ex.ToString());
}
}
catch (Exception ex)
{
Library.WriteErrorLog("Failed to restart Services: " + ex.ToString());
}
}

GetPrivateQueuesByMachine error when being called

I am trying to simply get a list of all the Private Queues on the Server from my PC.
The error I am getting is "Access to Message Queuing system is denied."
I have given full access to (Everyone, NETWORK SERVICE and Anonymous Logon) the queue on the as there is only 1 queue....
Please see attached error and code below:-
try
{
MessageQueue[] queueList =
MessageQueue.GetPrivateQueuesByMachine("xxx.xxx.x.xxx");//Error
occurs here
foreach (MessageQueue queueItem in queueList)
{
Console.WriteLine(queueItem.Path);
}
return created;
}
catch (MessageQueueException m)
{
Console.WriteLine(m.Message + m.MessageQueueErrorCode);
}
catch (SystemException s)
{
Console.WriteLine(s.Message + s.StackTrace);
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
On the computer manager of the target machine ("xxx.xxx.x.xxx" in your example) select "Services and applications" and then "Message Queuing". Right click on "Message Queuing", go to secuirty tab and add your account with full control. Thsi should give you access to the private queues on that machine

C# MSMQ MessageQueue Id - How to get Valid Guid

I tried to send a message in a Local Queue as well as in the Remote Queue.
The Sample Source is
Guid queueId;
try
{
MessageQueue rmQ = new MessageQueue("FormatName:Direct=TCP:192.168.5.26\\Private$\\RemoteQueue");
//MessageQueue rmQ = new MessageQueue(".\\Private$\\LocalQueue");
rmQ.Send("Once again Mr.John Please come here...");
queueId = rmQ.Id;
}
catch (ArgumentException ex)
{
throw ex;
}
catch (MessageQueueException ex)
{
throw ex;
}
catch (InvalidOperationException ex)
{
throw ex;
}
catch (Exception ex)
{
throw ex;
}
In all the Scenario I am getting Guid.Empy but the message is queuing successfully in the respective machine's Message Queue.
Kindly review the following snapshot
Kindly assist me how to get the Valid MessageQueue.Id
You are trying to access an ID of a private queue, which is unsupported. MSDN says:
Message Queuing sets the Id property when it creates the queue. This
property is only available for public queues.
See
https://msdn.microsoft.com/en-us/library/system.messaging.messagequeue.id(v=vs.110).aspx

How to handle WCF exceptions (consolidated list with code)

I'm attempting to extend this answer on SO to make a WCF client retry on transient network failures and handle other situations that require a retry such as authentication expiration.
Question:
What are the WCF exceptions that need to be handled, and what is the correct way to handle them?
Here are a few sample techniques that I'm hoping to see instead of or in addition to proxy.abort():
Delay X seconds prior to retry
Close and recreate a New() WCF client. Dispose the old one.
Don't retry and rethrow this error
Retry N times, then throw
Since it's unlikely one person knows all the exceptions or ways to resolve them, do share what you know. I'll aggregate the answers and approaches in the code sample below.
// USAGE SAMPLE
//int newOrderId = 0; // need a value for definite assignment
//Service<IOrderService>.Use(orderService=>
//{
// newOrderId = orderService.PlaceOrder(request);
//}
/// <summary>
/// A safe WCF Proxy suitable when sessionmode=false
/// </summary>
/// <param name="codeBlock"></param>
public static void Use(UseServiceDelegateVoid<T> codeBlock)
{
IClientChannel proxy = (IClientChannel)_channelFactory.CreateChannel();
bool success = false;
try
{
codeBlock((T)proxy);
proxy.Close();
success = true;
}
catch (CommunicationObjectAbortedException e)
{
// Object should be discarded if this is reached.
// Debugging discovered the following exception here:
// "Connection can not be established because it has been aborted"
throw e;
}
catch (CommunicationObjectFaultedException e)
{
throw e;
}
catch (MessageSecurityException e)
{
throw e;
}
catch (ChannelTerminatedException)
{
proxy.Abort(); // Possibly retry?
}
catch (ServerTooBusyException)
{
proxy.Abort(); // Possibly retry?
}
catch (EndpointNotFoundException)
{
proxy.Abort(); // Possibly retry?
}
catch (FaultException)
{
proxy.Abort();
}
catch (CommunicationException)
{
proxy.Abort();
}
catch (TimeoutException)
{
// Sample error found during debug:
// The message could not be transferred within the allotted timeout of
// 00:01:00. There was no space available in the reliable channel's
// transfer window. The time allotted to this operation may have been a
// portion of a longer timeout.
proxy.Abort();
}
catch (ObjectDisposedException )
{
//todo: handle this duplex callback exception. Occurs when client disappears.
// Source: https://stackoverflow.com/questions/1427926/detecting-client-death-in-wcf-duplex-contracts/1428238#1428238
}
finally
{
if (!success)
{
proxy.Abort();
}
}
}
EDIT: There seems to be some inefficiencies with closing and reopening the client multiple times. I'm exploring solutions here and will update & expand this code if one is found. (or if David Khaykin posts an answer I'll mark it as accepted)
After tinkering around with this for a few years, the code below is my preferred strategy (after seeing this blog posting from the wayback machine) for dealing with WCF retries and handling exceptions.
I investigated every exception, what I would want to do with that exception, and noticed a common trait; every exception that needed a "retry" inherited from a common base class. I also noticed that every permFail exception that put the client into an invalid state also came from a shared base class.
The following example traps every WCF exception a client could through, and is extensible for your own custom channel errors.
Sample WCF Client Usage
Once you generate your client side proxy, this is all you need to implement it.
Service<IOrderService>.Use(orderService=>
{
orderService.PlaceOrder(request);
}
ServiceDelegate.cs
Add this file to your solution. No changes are needed to this file, unless you want to alter the number of retries or what exceptions you want to handle.
public delegate void UseServiceDelegate<T>(T proxy);
public static class Service<T>
{
public static ChannelFactory<T> _channelFactory = new ChannelFactory<T>("");
public static void Use(UseServiceDelegate<T> codeBlock)
{
IClientChannel proxy = null;
bool success = false;
Exception mostRecentEx = null;
int millsecondsToSleep = 1000;
for(int i=0; i<5; i++) // Attempt a maximum of 5 times
{
// Proxy cann't be reused
proxy = (IClientChannel)_channelFactory.CreateChannel();
try
{
codeBlock((T)proxy);
proxy.Close();
success = true;
break;
}
catch (FaultException customFaultEx)
{
mostRecentEx = customFaultEx;
proxy.Abort();
// Custom resolution for this app-level exception
Thread.Sleep(millsecondsToSleep * (i + 1));
}
// The following is typically thrown on the client when a channel is terminated due to the server closing the connection.
catch (ChannelTerminatedException cte)
{
mostRecentEx = cte;
proxy.Abort();
// delay (backoff) and retry
Thread.Sleep(millsecondsToSleep * (i + 1));
}
// The following is thrown when a remote endpoint could not be found or reached. The endpoint may not be found or
// reachable because the remote endpoint is down, the remote endpoint is unreachable, or because the remote network is unreachable.
catch (EndpointNotFoundException enfe)
{
mostRecentEx = enfe;
proxy.Abort();
// delay (backoff) and retry
Thread.Sleep(millsecondsToSleep * (i + 1));
}
// The following exception that is thrown when a server is too busy to accept a message.
catch (ServerTooBusyException stbe)
{
mostRecentEx = stbe;
proxy.Abort();
// delay (backoff) and retry
Thread.Sleep(millsecondsToSleep * (i + 1));
}
catch (TimeoutException timeoutEx)
{
mostRecentEx = timeoutEx;
proxy.Abort();
// delay (backoff) and retry
Thread.Sleep(millsecondsToSleep * (i + 1));
}
catch (CommunicationException comException)
{
mostRecentEx = comException;
proxy.Abort();
// delay (backoff) and retry
Thread.Sleep(millsecondsToSleep * (i + 1));
}
catch(Exception e)
{
// rethrow any other exception not defined here
// You may want to define a custom Exception class to pass information such as failure count, and failure type
proxy.Abort();
throw e;
}
}
if (success == false && mostRecentEx != null)
{
proxy.Abort();
throw new Exception("WCF call failed after 5 retries.", mostRecentEx );
}
}
}
I started a project on Codeplex that has the following features
Allows efficient reuse of the client proxy
Cleans up all resources, including EventHandlers
Operates on Duplex channels
Operates on Per-call services
Supports config constructor, or by factory
http://smartwcfclient.codeplex.com/
It is a work in progress, and is very heavily commented. I'll appreciate any feedback regarding improving it.
Sample usage when in instance mode:
var reusableSW = new LC.Utils.WCF.ServiceWrapper<IProcessDataDuplex>(channelFactory);
reusableSW.Reuse(client =>
{
client.CheckIn(count.ToString());
});
reusableSW.Dispose();
we have a WCF client that deal with almost any type of failure at the server. The Catch list is very long but does not have to be. If you look closely, you will see that many exceptions are child definitions of the Exception Class (and a few other classes).
Thus you can simplify things a lot if you want to. That said, here are some typical errors that we catch:
Server timeout
Server too busy
Server unavailable.
Below links may help to handle WCF Exceptions:
http://www.codeproject.com/KB/WCF/WCFErrorHandling.aspx
http://msdn.microsoft.com/en-us/library/cc949036.aspx

Categories