Why am I looping in ActiveMQ QueueBrowser? - c#

This snippet keeps looping through the queue browser. Apache.NMS 1.5.1, Apache.NMS.ActiveMQ 1.5.6, Broker 5.8.0
Queue size is < 200
I checked prefetch, and it is still at default.
ActiveMQ with C# and Apache NMS - Count messages in queue suggests checking enumerator.Current in the loop, but I am already doing that.
I tried setting a large prefetch with ?jms.prefetchPolicy.all=50000, but it still loops.
IConnectionFactory connectionFactory = new ConnectionFactory(connectUri, "SNDTest");
using (IConnection conn = connectionFactory.CreateConnection(USERNAME, PASSWORD))
{
conn.Start();
using (ISession session = conn.CreateSession())
{
using (IQueueBrowser browser = session.CreateBrowser(errorQueue))
{
int i = 0;
var e = browser.GetEnumerator();
while (e.MoveNext())
{
i++;
IMessage m = e.Current as IMessage;
How do I stop the looping?

This could be related to some bugs that are fixed in the v5.9.0 snapshot builds such as, AMQ-4487. Try downloading a recent nightly build of the broker and running against that.

Related

EasyNetQ. Advanced API - Publish does not produce response on RabbitServer

Looking at EasyNetQ as replacement for our current library for MQ communication.
For Testing im trying to simply publish a number of messages to an exchange, using a custom naming strategy.
My method for publishing is in t he small test method below>
public void PublishTest()
{
var advancedBus = RabbitHutch.CreateBus("host=localhost;virtualHost=Test;username=guest;password=guest;").Advanced;
var routingKey = "SimpleMessage";
// declare some objects
var queue = advancedBus.QueueDeclare("Q.TestQueue.SimpleMessage");
var exchange = advancedBus.ExchangeDeclare("E.TestExchange.SimpleMessage", ExchangeType.Direct);
var binding = advancedBus.Bind(exchange, queue, routingKey);
var message = new SimpleMessage() {Test = "HELLO"};
for (int i = 0; i < 100; i++)
{
advancedBus.Publish(exchange, routingKey, true, true, new Message<SimpleMessage>(message));
}
advancedBus.Dispose();
}
The problem is that even thou the Exchange and Queue is created, and bound proper, publishing does not produce anything.
No messages hit the queue.
The graph in the Rabbit MQ management interface does not even show any activity on the exchange.
Am i missing something here? The code is basically taken straight from the documentation.
If im using the simple bus and simply just publish, an exchange is created and i can see via the management interface, that messages are being published.
Since the simple bus uses the advanced API to publish i assume that it is a setup issue that i am missing.
I hope someone can bring some insight:-)
/Thomas
I finally tracked down what was causing the problem.
It turns out that setting the parameter: immediate to true will cause the systems to throw exceptions.
the paramters is apparently not supported any more in the RabbitMQ client, see the discussion here: https://github.com/mikehadlow/EasyNetQ/issues/112
So the code below works just fine, mark the change from true to false in the publish method:
public void PublishTest()
{
var advancedBus = RabbitHutch.CreateBus("host=localhost;virtualHost=Test;username=guest;password=guest;").Advanced;
var routingKey = "SimpleMessage";
// declare some objects
var queue = advancedBus.QueueDeclare("Q.TestQueue.SimpleMessage");
var exchange = advancedBus.ExchangeDeclare("E.TestExchange.SimpleMessage", ExchangeType.Direct);
var binding = advancedBus.Bind(exchange, queue, routingKey);
var message = new SimpleMessage() {Test = "HELLO"};
for (int i = 0; i < 100; i++)
{
advancedBus.Publish(exchange, routingKey, true, false, new Message<SimpleMessage>(message));
}
advancedBus.Dispose();
}

ZeroMQ performance issue

I'm having an issue with ZeroMQ, which I believe is because I'm not very familiar with it.
I'm trying to build a very simple service where multiple clients connect to a server and sends a query. The server responds to this query.
When I use REQ-REP socket combination (client using REQ, server binding to a REP socket) I'm able to get close to 60,000 messages per second at server side (when client and server are on the same machine). When distributed across machines, each new instance of client on a different machine linearly increases the messages per second at the server and easily reaches 40,000+ with enough client instances.
Now REP socket is blocking, so I followed ZeroMQ guide and used the rrbroker pattern (http://zguide.zeromq.org/cs:rrbroker):
REQ (client) <----> [server ROUTER -- DEALER --- REP (workers running on different threads)]
However, this completely screws up the performance. I'm getting only around 4000 messages per second at the server when running across machines. Not only that, each new client started on a different machine reduces the throughput of every other client.
I'm pretty sure I'm doing something stupid. I'm wondering if ZeroMQ experts here can point out any obvious mistakes. Thanks!
Edit: Adding code as per advice. I'm using the clrzmq nuget package (https://www.nuget.org/packages/clrzmq-x64/)
Here's the client code. A timer counts how many responses are received every second.
for (int i = 0; i < numTasks; i++) { Task.Factory.StartNew(() => Client(), TaskCreationOptions.LongRunning); }
void Client()
{
using (var ctx = new Context())
{
Socket socket = ctx.Socket(SocketType.REQ);
socket.Connect("tcp://192.168.1.10:1234");
while (true)
{
socket.Send("ping", Encoding.Unicode);
string res = socket.Recv(Encoding.Unicode);
}
}
}
Server - case 1: The server keeps track of how many requests are received per second
using (var zmqContext = new Context())
{
Socket socket = zmqContext.Socket(SocketType.REP);
socket.Bind("tcp://*:1234");
while (true)
{
string q = socket.Recv(Encoding.Unicode);
if (q.CompareTo("ping") == 0) {
socket.Send("pong", Encoding.Unicode);
}
}
}
With this setup, at server side, I can see around 60,000 requests received per second (when client is on the same machine). When on different machines, each new client increases number of requests received at server as expected.
Server Case 2: This is essentially rrbroker from ZMQ guide.
void ReceiveMessages(Context zmqContext, string zmqConnectionString, int numWorkers)
{
List<PollItem> pollItemsList = new List<PollItem>();
routerSocket = zmqContext.Socket(SocketType.ROUTER);
try
{
routerSocket.Bind(zmqConnectionString);
PollItem pollItem = routerSocket.CreatePollItem(IOMultiPlex.POLLIN);
pollItem.PollInHandler += RouterSocket_PollInHandler;
pollItemsList.Add(pollItem);
}
catch (ZMQ.Exception ze)
{
Console.WriteLine("{0}", ze.Message);
return;
}
dealerSocket = zmqContext.Socket(SocketType.DEALER);
try
{
dealerSocket.Bind("inproc://workers");
PollItem pollItem = dealerSocket.CreatePollItem(IOMultiPlex.POLLIN);
pollItem.PollInHandler += DealerSocket_PollInHandler;
pollItemsList.Add(pollItem);
}
catch (ZMQ.Exception ze)
{
Console.WriteLine("{0}", ze.Message);
return;
}
// Start the worker pool; cant connect
// to inproc socket before binding.
workerPool.Start(numWorkers);
while (true)
{
zmqContext.Poll(pollItemsList.ToArray());
}
}
void RouterSocket_PollInHandler(Socket socket, IOMultiPlex revents)
{
RelayMessage(routerSocket, dealerSocket);
}
void DealerSocket_PollInHandler(Socket socket, IOMultiPlex revents)
{
RelayMessage(dealerSocket, routerSocket);
}
void RelayMessage(Socket source, Socket destination)
{
bool hasMore = true;
while (hasMore)
{
byte[] message = source.Recv();
hasMore = source.RcvMore;
destination.Send(message, message.Length, hasMore ? SendRecvOpt.SNDMORE : SendRecvOpt.NONE);
}
}
Where the worker pool's start method is:
public void Start(int numWorkerTasks=8)
{
for (int i = 0; i < numWorkerTasks; i++)
{
QueryWorker worker = new QueryWorker(this.zmqContext);
Task task = Task.Factory.StartNew(() =>
worker.Start(),
TaskCreationOptions.LongRunning);
}
Console.WriteLine("Started {0} with {1} workers.", this.GetType().Name, numWorkerTasks);
}
public class QueryWorker
{
Context zmqContext;
public QueryWorker(Context zmqContext)
{
this.zmqContext = zmqContext;
}
public void Start()
{
Socket socket = this.zmqContext.Socket(SocketType.REP);
try
{
socket.Connect("inproc://workers");
}
catch (ZMQ.Exception ze)
{
Console.WriteLine("Could not create worker, error: {0}", ze.Message);
return;
}
while (true)
{
try
{
string message = socket.Recv(Encoding.Unicode);
if (message.CompareTo("ping") == 0)
{
socket.Send("pong", Encoding.Unicode);
}
}
catch (ZMQ.Exception ze)
{
Console.WriteLine("Could not receive message, error: " + ze.ToString());
}
}
}
}
Could you post some source code or at least a more detailed explanation of your test case? In general the way to build out your design is to make one change at a time, and measure at each change. You can always move stepwise from a known working design to more complex ones.
Most probably the 'ROUTER' is the bottleneck.
Check out these related questions on this:
Client maintenance in ZMQ ROUTER
Load testing ZeroMQ (ZMQ_STREAM) for finding the maximum simultaneous users it can handle
ROUTER (and ZMQ_STREAM, which is just a variant of ROUTER) internally has to maintain the client mapping, hence IMO it can accept limited connections from a particular client. It looks like ROUTER can multiplex multiple clients, only as long as, each client has only one active connection.
I could be wrong here - but I am not seeing much proof to the contrary (simple working code that scales to multi-clients with multi-connections with ROUTER or STREAM).
There certainly is a very severe restriction on concurrent connections with ZeroMQ, though it looks like no one know what is causing it.
I have done done performance testing on calling a native unmanaged DLL function with various methods from C#:
1. C++/CLI wrapper
2. PInvoke
3. ZeroMQ/clrzmq
The last might be interesting for you.
My finding at the end of my performance test was that using the ZMQ binding clrzmq was not useful and produced a factor of 100 performance overhead after I tried to optimize the PInvoke calls within the source code of the binding. Therefore I have used the ZMQ without a binding but with PInvoke calls.these calls must be done with the cdecl convention and with the option "SuppressUnmanagedCodeSecurity" to get most speed.
I had to import just 5 functions which was fairly easy.
At the end the speed was a bit slower than a PInvoke call but with the ZMQ-in my case over "inproc".
This may give you the hint to try it without the binding, if speed is interesting for you.
This is not a direct answer for your question but may help you to increase performance in general.

The transaction aborted

im creating a C# and WCF service which picks up msgs from MSMQ.
This is using transactional MSMQ. within the business logic, there is a condition and that condition then places a new message on a different transactional queue however I seem to always get an exception thrown and not sure where to go from here
"System.Transactions.TransactionAbortedException: The transaction has aborted.\r\n at System.Transactions.TransactionStatePromotedAborted.CreateAbortingClone(InternalTransaction tx)\r\n at System.Transactions.DependentTransaction..ctor(IsolationLevel isoLevel, InternalTransaction internalTransaction, Boolean blocking)\r\n at System.Transactions.Transaction.DependentClone(DependentCloneOption cloneOption)\r\n at System.Transactions.TransactionScope.SetCurrent(Transaction newCurrent)\r\n at System.Transactions.TransactionScope.PushScope()\r\n at System.Transactions.TransactionScope..ctor(TransactionScopeOption scopeOption)\r\n at TMC.Services.Implementation.InboundMessageHandler.Msmq.MsmqDispatcher.Dispatch(String queueFormatAndLocation, Object itemToPlaceOnQueue, Boolean traceMessage) in E:\Msmq\MsmqDispatcher.cs:line 39\r\n at TMC.Services.Implementation.InboundMessageHandler.OmhDispatcher.AckNackDispatcher.SendAckTo
Tg(SendAckToTgRequest request) in E:\AckNackDispatcher.cs:line 38"
Any ideas at all?
the code for when it is placing it on the queue:
var queue = new MessageQueue(queueFormatAndLocation);
var msg = new System.Messaging.Message {Body = itemToPlaceOnQueue, Priority = MessagePriority.High, UseDeadLetterQueue = true, UseTracing = traceMessage};
using (var ts = new TransactionScope(TransactionScopeOption.Required))
{
queue.Send(msg, MessageQueueTransactionType.Automatic); // send the message
ts.Complete(); // complete the transaction
}
in terms of the queueFormatAndLocation, it is correct:
"FormatName:Direct=OS:.\private$\AckMsgs"
This helps and seems to work:
http://msdn.microsoft.com/query/dev10.query?appId=Dev10IDEF1&l=EN-US&k=k(%22SYSTEM.MESSAGING.MESSAGEQUEUETRANSACTION.%23CTOR%22);k(SOLUTIONITEMSPROJECT);k(TargetFrameworkMoniker-%22.NETFRAMEWORK%2cVERSION%3dV4.0%22);k(DevLang-CSHARP)&rd=true
http://msdn.microsoft.com/query/dev10.query?appId=Dev10IDEF1&l=EN-US&k=k(%22SYSTEM.MESSAGING.MESSAGEQUEUE.%23CTOR%22);k(SOLUTIONITEMSPROJECT);k(TargetFrameworkMoniker-%22.NETFRAMEWORK%2cVERSION%3dV4.0%22);k(DevLang-CSHARP)&rd=true
basically using the MessageQueueTransasction and MessageQueue class. the reason for the MQT is to use it within an existing transaction (in my scenario). this seems to work.
code:
using (var mqt = new MessageQueueTransaction())
{
mqt.Begin();
MessageQueue mq = new MessageQueue(queueFormatAndLocation);
mq.Send(itemToPlaceOnQueue, mqt);
mqt.Commit();
}

Mongodb FindAll not work as exptected

[TestMethod]
public void TestLoop()
{
var server = MongoServer.Create(
#"mongodb://user:password#dbh74.mongolab.com:2700/XXX");
var database = server["XXX"];
MongoCollection<Item> sourceCollection =database.GetCollection<Item>("Item");
var counter = 0;
int batchSize = 200;
List<item> batch = new List<item>();
foreach (var item in sourceCollection.FindAll().SetBatchSize(batchSize))
{
counter++;
batch.Add(item);
}
}
This is a simple test function to retrieve a collection for testing purpose. It work fine before but it is broken and throw the following error.
Unable to read data from the transport connection: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.
This error is throw as the cursor want to get the next batch of data. It seems the connection is dropped so I modified my code for a work around to force reconnect.
[TestMethod]
public void TestLoop()
{
var server = MongoServer.Create(
#"mongodb://user:password#dbh74.mongolab.com:2700/XXX");
var database = server["XXX"];
MongoCollection<Item> sourceCollection =database.GetCollection<Item>("Item");
var counter = 0;
int batchSize = 200;
List<item> batch = new List<item>();
foreach (var item in sourceCollection.FindAll().SetBatchSize(batchSize))
{
//serverX.Reconnect();
counter++;
if (counter% batchSize == 0)
{
server.Reconnect();
}
batch.Add(item);
}
}
I want to know what's wrong of my orginal code. The only difference thing is my mongodb hosting mongolab just promoted its version to 2.0.2. Any hints is appreciate.
Resolved. It is not a matter of code or db version. There are application running in background and consume the network resource.
After closing that application and re-run the test. The test go fine.

ActiveMQ with C# and Apache NMS - Count messages in queue

I'm using ActiveMQ to send and receive messages using a C# app. However I'm having some difficulty just getting a count of the messages in the queue.. Here's my code:
public int GetMessageCount()
{
int messageCount = 0;
Uri connecturi = new Uri(this.ActiveMQUri);
IConnectionFactory factory = new NMSConnectionFactory(connecturi);
using (IConnection connection = factory.CreateConnection())
using (ISession session = connection.CreateSession())
{
IDestination requestDestination = SessionUtil.GetDestination(session, this.QueueRequestUri);
IQueueBrowser queueBrowser = session.CreateBrowser((IQueue)requestDestination);
IEnumerator messages = queueBrowser.GetEnumerator();
while(messages.MoveNext())
{
messageCount++;
}
connection.Close();
session.Close();
connection.Close();
}
return messageCount;
}
I thought I could use the QueueBrowser to get the count, but the IEnumerator it returns is always empty. I got the idea of using QueueBrowser from this page, but maybe there is another way I should be doing this?
Update:
The solution to the 'infinite loop' issue I found when going through the enumerator was solved by accessing the current message. It now only goes through the loop once (which is correct as there is only one message in the queue).
New while loop is:
while(messages.MoveNext())
{
IMessage message = (IMessage)messages.Current;
messageCount++;
}
I don't have an ActiveMq with me right now so I can not try it
but I think the problem is you are not starting the connection. Try like this :
using (IConnection connection = factory.CreateConnection())
{
connection.start ();
using (ISession session = connection.CreateSession())
{
//Whatever...
}
}

Categories