Async sends in .NET ActiveMQ - performance

I'm looking to increase the performance of a high-throughput producer that I'm writing against ActiveMQ, and according to this useAsyncSend will:
Forces the use of Async Sends which adds a massive performance boost;
but means that the send() method will return immediately whether the
message has been sent or not which could lead to message loss.
However I can't see it making any difference to my simple test case.
Using this very basic application:
const string QueueName = "....";
const string Uri = "....";
static readonly Stopwatch TotalRuntime = new Stopwatch();
static void Main(string[] args)
{
TotalRuntime.Start();
SendMessage();
Console.ReadLine();
}
static void SendMessage()
{
var session = CreateSession();
var destination = session.GetQueue(QueueName);
var producer = session.CreateProducer(destination);
Console.WriteLine("Ready to send 700 messages");
Console.ReadLine();
var body = new byte[600*1024];
Parallel.For(0, 700, i => SendMessage(producer, i, body, session));
}
static void SendMessage(IMessageProducer producer, int i, byte[] body, ISession session)
{
var message = session.CreateBytesMessage(body);
var sw = new Stopwatch();
sw.Start();
producer.Send(message);
sw.Stop();
Console.WriteLine("Running for {0}ms: Sent message {1} blocked for {2}ms",
TotalRuntime.ElapsedMilliseconds,
i,
sw.ElapsedMilliseconds);
}
static ISession CreateSession()
{
var connectionFactory = new ConnectionFactory(Uri)
{
AsyncSend = true,
CopyMessageOnSend = false
};
var connection = connectionFactory.CreateConnection();
connection.Start();
var session = connection.CreateSession(AcknowledgementMode.AutoAcknowledge);
return session;
}
I get the following output:
Ready to send 700 messages
Running for 2430ms: Sent message 696 blocked for 12ms
Running for 4275ms: Sent message 348 blocked for 1858ms
Running for 5106ms: Sent message 609 blocked for 2689ms
Running for 5924ms: Sent message 1 blocked for 2535ms
Running for 6749ms: Sent message 88 blocked for 1860ms
Running for 7537ms: Sent message 610 blocked for 2429ms
Running for 8340ms: Sent message 175 blocked for 2451ms
Running for 9163ms: Sent message 89 blocked for 2413ms
.....
Which shows that each message takes about 800ms to send and the call to session.Send() blocks for about two and a half seconds. Even though the documentation says that
"send() method will return immediately"
Also these number are basically the same if I either change the parallel for to a normal for loop or change the AsyncSend = true to AlwaysSyncSend = true so I don't believe that the async switch is working at all...
Can anyone see what I'm missing here to make the send asynchronous?
After further testing:
According to ANTS performance profiler that vast majority of the runtime is being spent waiting for synchronization. It appears that the issue is that the various transport classes block internally through monitors. In particular I seem to get hung up on the MutexTransport's OneWay method which only allows one thread to access it at a time.
It looks as though the call to Send will block until the previous message has completed, this explains why my output shows that the first message blocked for 12ms, while the next took 1858ms. I can have multiple transports by implementing a connection-per-message pattern which improves matters and makes the message sends work in parallel, but greatly increases the time to send a single message, and uses up so many resources that it doesn't seem like the right solution.
I've retested all of this with 1.5.6 and haven't seen any difference.

As always the best thing to do is update to the latest version (1.5.6 at the time of this writing). A send can block if the broker has producer flow control enabled and you've reached a queue size limit although with async send this shouldn't happen unless you are sending with a producerWindowSize set. One good way to get help is to create a test case and submit it via a Jira issue to the NMS.ActiveMQ site so that we can look into it using your test code. There have been many fixes since 1.5.1 so I'd recommend giving that new version a try as it could already be a non-issue.

Related

Connection time out in jpos client

I am using jpos client (In one of the class of java Spring MVC Program) to connect the ISO8585 based server, however due to some reason server is not able to respond back, due to which my program keeps waiting for the response and results in hanging my program. So what is the proper way to implement connection timeout?
My client program look like this:
public FieldsModal sendFundTransfer(FieldsModal field){
try {
JposLogger logger = new JposLogger(ISO_LOG_LOCATION);
org.jpos.iso.ISOPackager customPackager = new GenericPackager(ISO_PACKAGER);
ISOChannel channel = new PostChannel(ISO_SERVER_IP, Integer.parseInt(ISO_SERVER_PORT), customPackager);// live
logger.jposlogconfig(channel);
channel.connect();
log4j.info("Connection established using PostChannel");
ISOMsg m = new ISOMsg();
m.set(0, field.getMti());
//m.set(2, field.getField2());
m.set(3, field.getField3());
m.set(4, field.getField4());
m.set(11, field.getField11());
m.set(12, field.getField12());
m.set(17, field.getField17());
m.set(24, field.getField24());
m.set(32, field.getField32());
m.set(34, field.getField34());
m.set(41, field.getField41());
m.set(43, field.getField43());
m.set(46, field.getField46());
m.set(49, field.getField49());
m.set(102,field.getField102());
m.set(103,field.getField103());
m.set(123, field.getField123());
m.set(125, field.getField125());
m.set(126, field.getField126());
m.set(127, field.getField127());
m.setPackager(customPackager);
System.out.println(ISOUtil.hexdump(m.pack()));
channel.send(m);
log4j.info("Message has been send");
ISOMsg r = channel.receive();
r.setPackager(customPackager);
System.out.println(ISOUtil.hexdump(r.pack()));
channel.disconnect();
}catch (Exception err) {
System.out.println("sendFundTransfer : " + err);
}
return field;
}
Well the real proper way would be to use Q2. Given you don't need a persistent connection you coud just set a timeout for the channel.
PostChannel channel = new PostChannel(ISO_SERVER_IP, Integer.parseInt(ISO_SERVER_PORT), customPackager);// live
channel.setTimeout(timeout); //timeout in millies.
This way channel will autodisconnect if nothing happens during the time specified by timeout , and your call to receive will throw an exception.
The alternative is using Q2 and a mux (see QMUX, for which you need to run Q2, or ISOMUX which is kind of deprecated).

JmsTemplate's browseSelected not retrieving all messages

I have some Java code that reads messages from an ActiveMQ queue. The code uses a JmsTemplate from Spring and I use the "browseSelected" method to retrieve any messages from the queue that have a timestamp in their header older than 7 days (by creating the appropriate criteria as part of the messageSelector parameter).
myJmsTemplate.browseSelected(myQueue, myCriteria, new BrowserCallback<Integer>() {
#Override
public Integer doInJms(Session s, QueueBrowser qb) throws JMSException {
#SuppressWarnings("unchecked")
final Enumeration<Message> e = qb.getEnumeration();
int count = 0;
while (e.hasMoreElements()) {
final Message m = e.nextElement();
final TextMessage tm = (TextMessage) MyClass.this.jmsQueueTemplate.receiveSelected(
MyClass.this.myQueue, "JMSMessageID = '" + m.getJMSMessageID() + "'");
myMessages.add(tm);
count++;
}
return count;
}
});
The BrowserCallback's "doInJms" method adds the messages which match the criteria to a list ("myMessages") which subsequently get processed further.
The issue is that I'm finding the code will only process 400 messages each time it runs, even though there are several thousand messages which match the criteria specified.
When I previously used another queueing technology with this code (IBM MQ), it would process all records which met the criteria.
I'm wondering whether I'm experiencing an issue with ActiveMQ's prefetch limit: http://activemq.apache.org/what-is-the-prefetch-limit-for.html
Versions: ActiveMQ 5.10.1 and Spring 3.2.2.
Thanks in advance for any assistance.
The broker will only return up to 400 message by default as configured by the maxBrowsePageSize option in the destination policies. You can increase that value but must use caution as the messages are paged into memory and as such can lead you into an OOM situation.
You must always remember that a message broker is not a database, using it as one will generally end in tears.

email read from EWS (exchange web service) server cannot process this request error c#

I have a task where i need to check the emails delivered to my mailbox and read them ,based on subject i have to do some task. But for demo purpose I have put only the basic functionality of just updating the email read status
The basic connection and creating service object everything is fine:
///////////
NetworkCredential credentials = new NetworkCredential(securelyStoredEmail, securelyStoredPassword);
ExchangeService _service = new ExchangeService(ExchangeVersion.Exchange2010_SP2);
_service.Credentials = credentials;
_service.AutodiscoverUrl("User1#contoso.com");
/////////////////////////
Here Everything works fine. However I will invoke the below method for every 60s using observable event of reactive linq. THis is to go and poll the my emailbox and read 100 emails for every 60 seconds.
Everything works fine till sometime. Sometimes when the control reaches the line of code inside parallel.foreach loop, it shows error message like 'server cannot process this request now. Please try later' something like this. THis error comes exactly at the line
var email = EmailMessage.Bind(_service, findItemsResult.Id, emailProps);
so for every 60 seconds, i will get this error sometimes.sometimes it works fine.
Below is the method which is executed for every 60seconds. Its like i try to read the emails from "myaccount.com" for every 60s and i vil get the error 'server cannot process'.
internal void GetEmailsFrommymailbox()
{
try
{
var view = new ItemView(100);
var userMailbox = new Mailbox(userMailbox);
var folderId = new FolderId(WellKnownFolderName.Inbox, userMailbox);
SearchFilter sf = new SearchFilter.SearchFilterCollection(LogicalOperator.And,
new SearchFilter.IsEqualTo(EmailMessageSchema.IsRead, false));
var findResults = _service.FindItems(folderId, sf, view);
var emailProps = new PropertySet(ItemSchema.MimeContent, ItemSchema.Body,
ItemSchema.InternetMessageHeaders);
Parallel.ForEach(findResults, findItemsResult =>
{
///////////// this is the line where i get error////////
var email = EmailMessage.Bind(_service, findItemsResult.Id, emailProps);
//// above is the place where i get error
var emailMatching = email;
try
{
email.IsRead = true;
email.Update(ConflictResolutionMode.AutoResolve);
}
catch (Exception emailreadFromBccException)
{
Logger.Warn(emailreadFromBccException + " Unable to update email read status");
}
});
}
}
Your getting that error because you being throttled https://msdn.microsoft.com/en-us/library/office/jj945066%28v=exchg.150%29.aspx and your being throttled because you code isn't very efficient.
Instead of doing
Parallel.ForEach(findResults, findItemsResult =>
{
///////////// this is the line where i get error////////
var email = EmailMessage.Bind(_service, findItemsResult.Id, emailProps);
You should use LoadPropertiesFromItems http://blogs.msdn.com/b/exchangedev/archive/2010/03/16/loading-properties-for-multiple-items-with-one-call-to-exchange-web-services.aspx . Which will reduce the number of call you need to make to the server.
I would also suggest you use Streaming notification https://msdn.microsoft.com/en-us/library/office/hh312849%28v=exchg.140%29.aspx?f=255&MSPPError=-2147217396 which will mean you won't need to poll the server every 60 seconds and just take an action when a new item arrives.
Cheers
Glen

SmtpClient.SendAsync blocking my ASP.NET MVC Request

I have a Action that sends a simple email:
[HttpPost, ActionName("Index")]
public ActionResult IndexPost(ContactForm contactForm)
{
if (ModelState.IsValid)
{
new EmailService().SendAsync(contactForm.Email, contactForm.Name, contactForm.Subject, contactForm.Body, true);
return RedirectToAction(MVC.Contact.Success());
}
return View(contactForm);
}
And a email service:
public void SendAsync(string fromEmail, string fromName, string subject, string body, bool isBodyHtml)
{
MailMessage mailMessage....
....
SmtpClient client = new SmtpClient(settingRepository.SmtpAddress, settingRepository.SmtpPort);
client.EnableSsl = settingRepository.SmtpSsl;
client.Credentials = new NetworkCredential(settingRepository.SmtpUserName, settingRepository.SmtpPassword);
client.SendCompleted += client_SendCompleted;
client.SendAsync(mailMessage, Tuple.Create(client, mailMessage));
}
private void client_SendCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
Tuple<SmtpClient, MailMessage> data = (Tuple<SmtpClient, MailMessage>)e.UserState;
data.Item1.Dispose();
data.Item2.Dispose();
if (e.Error != null)
{
}
}
When I send a email, I am using Async method, then my method SendAsync return immediately, then RedirectToAction is called. But the response(in this case a redirect) isnĀ“t sent by ASP.NET until client_SendCompleted is completed.
Here's what I'm trying to understand:
When watching the execution in Visual Studio debugger, the SendAsync returns immediately (and RedirectToAction is called), but nothing happens in the browser until email is sent?
If i put a breakpoint inside client_SendCompleted, the client stay at loading.... until I hit F5 at debugger.
This is by design. ASP.NET will automatically wait for any outstanding async work to finish before finishing the request if the async work was kicked off in a way that calls into the underlying SynchronizationContext. This is to ensure that if your async operation tries to interact with the HttpContext, HttpResponse, etc. it will still be around.
If you want to do true fire & forget, you need to wrap your call in ThreadPool.QueueUserWorkItem. This will force it to run on a new thread pool thread without going through the SynchronizationContext, so the request will then happily return.
Note however, that if for any reason the app domain were to go down while your send was still in progress (e.g. if you changed the web.config file, dropped a new file into bin, the app pool recycled, etc.) your async send would be abruptly interrupted. If you care about that, take a look at Phil Haacks WebBackgrounder for ASP.NET, which let's you queue and run background work (like sending an email) in such a way that will ensure it gracefully finishes in the case the app domain shuts down.
This is an interesting one. I've reproduced the unexpected behaviour, but I can't explain it. I'll keep digging.
Anyway the solution seems to be to queue a background thread, which kind of defeats the purpose in using SendAsync. You end up with this:
MailMessage mailMessage = new MailMessage(...);
SmtpClient client = new SmtpClient(...);
client.SendCompleted += (s, e) =>
{
client.Dispose();
mailMessage.Dispose();
};
ThreadPool.QueueUserWorkItem(o =>
client.SendAsync(mailMessage, Tuple.Create(client, mailMessage)));
Which may as well become:
ThreadPool.QueueUserWorkItem(o => {
using (SmtpClient client = new SmtpClient(...))
{
using (MailMessage mailMessage = new MailMessage(...))
{
client.Send(mailMessage, Tuple.Create(client, mailMessage));
}
}
});
With .Net 4.5.2, you can do this with ActionMailer.Net:
var mailer = new MailController();
var msg = mailer.SomeMailAction(recipient);
var tcs = new TaskCompletionSource<MailMessage>();
mailer.OnMailSentCallback = tcs.SetResult;
HostingEnvironment.QueueBackgroundWorkItem(async ct =>
{
msg.DeliverAsync();
await tcs.Task;
Trace.TraceInformation("Mail sent to " + recipient);
});
Please read this first: http://www.hanselman.com/blog/HowToRunBackgroundTasksInASPNET.aspx
I sent the bug to Microsoft Connect https://connect.microsoft.com/VisualStudio/feedback/details/688210/smtpclient-sendasync-blocking-my-asp-net-mvc-request

HttpWebRequest.BeginGetResponse completes too late

I use in my code calls to HttpWebRequest.BeginGetResponse() method to get data from my server. The server produces content that may range from few KB to few GB.
My problem is that HttpWebRequest.BeginGetResponse completes too late. It should complete immediately after the connection to the server is established and the HTTP header is received.
Here is sample code using GET method:
public bool StartDownload()
{
try
{
HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create(m_getUrl);
myHttpWebRequest.Method = "GET";
// Start the asynchronous request.
m_requestState = new RequestState();
m_requestState.request = myHttpWebRequest;
myHttpWebRequest.BeginGetResponse(new AsyncCallback(ResponseCompleted), m_requestState);
}
catch (Exception)
{
m_requestState = null;
}
return m_requestState != null;
}
private void ResponseCompleted(IAsyncResult result)
{
RequestState myRequestState = (RequestState)result.AsyncState;
HttpWebRequest myHttpWebRequest = myRequestState.request;
m_logger.LogMessage("ResponseCompleted notification received!");
HttpWebResponse response = null;
try
{
response = (HttpWebResponse)myHttpWebRequest.EndGetResponse(result);
}
catch (Exception)
{
}
.......
}
I run the code using "http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.39.1.tar.bz2" for example and the result looks like:
hh:mm:ss.ms
12:51:30.9440000 - Download started!
12:53:04.8520000 - ResponseCompleted notification received!
12:53:04.8560000 - Header received!
12:53:04.8570000 - DataReceived: 524288 bytes
.........................................
12:53:04.8940000 - DataReceived: 78818 bytes
12:53:04.8940000 - Request data received!
12:53:04.8940000 - Received bytes: 76100578
The problem can be easily detected in the log. It is not possible to spend more that one minute to connect and 38 ms to download about 72.5 MB.
It seems that the data is downloaded somewhere on the phone and the RequestComplete notification is sent to the application only when the full content is available locally. This is not OK for me because I need to show progress for the operation.
I get the same result on the device and emulator for WP7 (also on WP7.1).
I run same code on Windows desktop and it run correctly: the request completes within one second and the rest of the download takes about 1-2 minutes.
Is there any solution on WP7 or WP 7.1?
The newly introduced WP 7.1 API "Background File Transfers" does not help because I need full control over the HTTP headers and content. Not all HTTP requests that I make to the server produce files as output.
Thank you!
Mihai
You need to disable response buffering if you want to stream the data down. You can do this by setting AllowReadStreamBuffering to false.
HttpWebRequest myHttpWebRequest = WebRequest.CreateHttp(m_getUrl);
myHttpWebRequest.Method = "GET";
myHttpWebRequest.AllowReadStreamBuffering = false;

Resources