I have reached a point where I will have to send email notifications to my users, fro any event they have subscribed to. My service is not large, but nothing stops it from becoming one, thus I would like to be prepared.
Currently, I am handling those emails using Spring's mail sender in a fairly synchronous manner (grabbing a bunch of subscribed email addresses from a collection and sending them a mail) However, one can see how unusable this approach may soon become. Thus I am striving for a little bit more parallelism.
Multiple threads may help the situation unless there are too many of them at the same time. I guess |I will need something like an in-memory queue, which could send batches of emails at certain intervals, opening a new thread. Threads which are finished will eb collected in a thread pool and reused.
Suggestions? Perhaps my approach is too complex. Perhaps Spring already offers a way to alleviate the blocking and synchronism. I'd be glad to know.
Rather than send one email to each user, just send a single email to all of the users at once. In other words, make one mail and add every user to the destination list. Then your SMTP server will worry about duplicating it and sending copies to each person.
Related
My server requires sending emails pretty frequently. The emails are heavy; they have attachments as well as inline images in them.
My present code blocks code until an email is sent. (loosing 5 to 6 seconds for every email)
What is the best approach for handling the emails with out blocking the main code flow?
If you are suggesting threads, please elaborate on how efficiently it could be handled?
There are multiple ways to achieve this functionality.
Synchronous Call
This is the one which you are already using. Code (synchronously) invokes Java Mail API and waits for API to complete the execution. The process may take time depending on the complexity of building the email message (fetching records from Database, reading images/documents (attachments), communication with Mail Server etc.
Trade-offs
For individual requests(web/desktop), response latency will increase based on the time it takes to construct and send email.
An exception in sending email, may require redo of entire process (if retried).
Transactional data (e.g. DB) may be rolled back, due to exception while sending email. This may not be desired behavior.
Overall application latency will increase, if similar functionality is invoked by multiple users concurrently.
Email retry functionality may not be possible, if email sending code is tightly coupled with other functional code.
Multithreading Approach
Create a separate thread to asynchronously send an email. Calling code need not have to wait for Email send functionality to complete and execute rest of the code. Ideally, should make use of ThreadPool, instead of blandly creating new threads.
Trade-offs
Though, request latency will go down, it is still not reliable. Any exception occurred while constructing/sending email may result into, no email sent to user.
Email sending functionality can't be distributed across multiple machines.
Retry functionality is possible, since email code is separated into separate class. This class can be independently called, without a need of redoing other things.
Asynchronous Processing
Create a class, which accepts Email request and stores it in either database or messaging infrastructure (e.g. JMS). The message listeners will process the task as and when it arrives and update the status against each task.
Trade-offs
Email requests can be processed in distributed mode.
Retry email possible, without having any side effects.
Complex implementation as multiple components are involved in processing, persisting email requests.
You can efficiently do this if you spawn a thread for every email you have to send.
One way to do it is as follows:
You would need a class that is just a pure extension of Thread:
public class MailSenderThread extends Thread {
#Override
public void run() {
try {
// Code to send email
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
And when you want to send email, you can do:
new MailSenderThread().start();
That is the shortest/easiest way I could think of.
You can refer to an example in my public repository as well. It's off-topic but it gets the concept.
I have problem with counting responses from response queue. I mean, once per day we run a job which gather some data from db and send them to queue. When we receive all responses we should shutdown connection. The problem is how we can check if all responses arrived ? Keeping this in global variable is risky because of concurrence issue. Any idea ? I am quite new in JMS so maybe solution is obvious but I dont see it.
I don't know what your stack is or whatever tools you might be using to accomplish this but I've got this in mind and this might help you out (hopefully).
Generate a hash for each job you plan on queuing and store it in a concurrent list/map. (i.e: ConcurrentHashMap)
Send the job to the queue.
Once the job is done and sends back a response, reproduce the hash and store it a separate concurrent list/map that holds all the jobs that are done.
Now that you have two lists of all the jobs supposed to be executed and the jobs that you got a response from. There multiple ways to accomplish this. If you lookup Java Concurrency, you'd find plenty of tutorials and documentation. I like to use CyclicBarrierandCountDownLatch`. If plan on using any of these methods, take extra precautions to prevent your application from hanging or worse, a filthy memory leak.
OR, you could simply check on how many queuing requests and responses you've and if they are equal to each other, drop the connection.
I have a piece of middleware that sits between two JMS queues. From one it reads, processes some data into the database, and writes to the other.
Here is a small diagram to depict the design:
With that in mind, I have some interesting logic that I would like to integrate into the service.
Scenario 1: Say the middleware service receives a message from Queue 1, and hits the database to store portions of that message. If all goes well, it constructs a new message with some data, and writes it to Queue 2.
Scenario 2: Say that the database complains about something, when the service attempts to perform some logic after getting a message from Queue 1.In this case, instead of writing a message to Queue 2, I would re-try to perform the database functionality in incremental timeouts. i.e Try again in 5 sec., then 30 sec, then 1 minute if still down. The catch of course, is to be able to read other messages independently of this re-try. i.e Re-try to process this one request, while listening for other requests.
With that in mind, what is both the correct and most modern way to construct a future proof solution?
After reading some posts on the net, it seems that I have several options.
One, I could spin off a new thread once a new message is received, so that I can both perform the "re-try" functionality and listen to new requests.
Two, I could possibly send the message back to the Queue, with a delay. i.e If the process failed to execute in the db, write the message to the JMS queue by adding some amount of delay to it.
I am more fond of the first solution, however, I wanted to get the opinion of the community if there is a newer/better way to solve for this functionality in java 7. Is there something built into JMS to support this sort of "send message back for reprocessing at a specific time"?
JMS 2.0 specification describes the concept of delayed delivery of messages. See "What's new" section of https://java.net/projects/jms-spec/pages/JMS20FinalReleaseMany JMS providers have implemented the delayed delivery feature.
But I wonder how the delayed delivery will help your scenario. Since the database writes have issues, subsequent messages processing and attempt to write to database might end up in same situation. I guess it might be better to sort out issues with database updates and then pickup messages from queue.
The scenario is the sending of a password reset mail to the user from a web request (and possibly other mail related tasks in the future).
The arguments I bring to the table for queuing:
I believe web requests should be handled as fast as possible
Decoupling the send action from the request, more easily allows externalization of the mail system (if required in the future)
The arguments I recognize against queuing:
The user does not get feedback if something goes wrong during the sending of the message
What are more arguments in this discussion? And to those in favor of queuing, how would you implement the queue? Scheduled action? Infinite dequeuing task (with interval, of course)?
Thanks!
I would suggest you to decouple actual sending of mail from your app business logic.
Do this asynchronously: Use queue or at least different thread for sending such notifications.
Sending of email could be time consuming operation,
even if you use your own internal mail server which is close to your app.
SMTP conversation consists of several requests/responses.
Do not treat sending of a mail as a transactional action.
When target SMTP server replies with 250 OK as a response for DATA command - it just takes responsibility for this mail nothing else.
Delivery could fail in future if next server in the chain is not able to deliver mail (read about DSN, aka bounce).
Last but not least think about failure modes.
What if your business critical functionality is slowed down / blocked by auxiliary one (email notification), not good I guess.
You definitely don't want to do the send synchronously since the mail server may be slow.
Send a JMS message and use an MDB to send the email.
In a Java EE 6+ scenario you can use #Asynchronous annotation in a EJB method. It returns a Future<V>. So you can continue with proccesing and ask later for task ending, while it is executed in another thread.
So you can accept a lot of request fastly, you decouple the send action from request, and you can get feedback.
http://docs.oracle.com/javaee/6/tutorial/doc/gkkqg.html
You may think that requests should be serviced as fast as possible, but what about the user? What does he think?
The user needs his password reset. He doesn't care how long that takes. If he can't complete that request he can't do anything at all.
Don't queue.
I think u should go to queue. Because it help in fast performance and to check whether the password reset request is arrived from correct source.
So u can use Map for queue implementation. Because in map u can use email id as key and a unique request reference as value. And this map element should be deleted within a time period.
Also for fast email service u can create a simple thread class that send emails and start a new thread by passing some data arguments in it. and scheduling will automatically managed by web container for these threads.
Just start scaling APNS provider program unfortunately I am really new to networking protocol implementation.
The provider now only runs on one thread and it's just handling a tiny amount of notifications. Now I want to increase its capability to send significantly more than before.
My questions are:
According to Apple doc I can maintain multiple connections to gateways. So my understanding is that I run multithreads in the provider program and maintain a separate connection in each. Is this right?
It first one is right the real difficulty for me comes: my program polls a queue database every 5 seconds to check new message that's to be sent. I do not think it's a good idea for all the threads to poll this same database because there should be duplicate message same to users. How to solve this problem?
I have seen the connections pooling but I do not really understand what that is. Is that the thing I need to study and use? If it is can someone offer an brief explanation regarding what it is and how to use it?
Thanks guys!
Your first assumption is reasonable. Each thread should have its own connection.
As for the second point, the access to the DB that contains the new messages should be synchronized. For example, you can access that DB by a synchronized method that fetches a message or several messages that haven't been processed yet, and marks them as being processed. Two threads can't access that method at the same time, and therefore won't get the same messages.
Another option is to put the messages in memory in a blocking quoue (with the DB only serving for backup in case of a crash). The threads can request an item from the queue, which would block them until an item is available.