Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating a background Thread for sending email

I need to send a email during registration process , so for this reason i am using Java Mail API , this is working fine , but observed that the email process is taking nearly 6 seconds (which is too long ) so Ajax call making the user wait too long for response

so for this reason i have decided to use background thread for sending email so the user need not wait for the Ajax call response (Jersey REST Web Service call)

My question is it a good practice to creating threads in a webapplication for every request ??

@Path("/insertOrUpdateUser")
public class InsertOrUpdateUser {
        final static Logger logger = Logger.getLogger(InsertOrUpdateUser.class);
        @GET
        @Consumes("application/text")
        @Produces("application/json")
        public String getSalesUserData(@QueryParam(value = "empId") String empId
                        )
                        throws JSONException, SQLException {
                JSONObject final_jsonobject = new JSONObject();
            ExecutorService executorService = Executors.newFixedThreadPool(10);
                                executorService.execute(new Runnable() {
                                 public void run() {
                                         try {
                                                        SendEmailUtility.sendmail(emaildummy);
                                                } catch (IOException e) {
                                                        logger.error("failed",e);

                                                }
                                 }
                              });

                        }


                } catch (SQLException e) {

                } catch (Exception e) {


                }


                   finally {

                        }


                return response;
        }




}

And this is my Utility class for sending email

public class SendEmailUtility
{
    public static String sendmail(String sendto)
        throws IOException
    {
        String result = "fail";
        Properties props_load = getProperties();
        final String username = props_load.getProperty("username");
        final String password = props_load.getProperty("password");
        Properties props_send = new Properties();
        props_send.put("mail.smtp.auth", "true");
        props_send.put("mail.smtp.starttls.enable", "true");
        props_send.put("mail.smtp.host", props_load.getProperty("mail.smtp.host"));
        props_send.put("mail.smtp.port", props_load.getProperty("mail.smtp.port"));

        Session session = Session.getInstance(props_send,
            new javax.mail.Authenticator() {
                @Override
                protected PasswordAuthentication getPasswordAuthentication()
                {
                    return new PasswordAuthentication(username, password);
                }
            });

        try {
            Message message = new MimeMessage(session);
            message.setFrom(new InternetAddress(props_load.getProperty("setFrom")));
            message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(sendto));
            message.setText("Some Text to be send in mail");
            Transport.send(message);
            result = "success";
        } catch (MessagingException e) {
            result = "fail";
            logger.error("Exception Occured - sendto: " + sendto, e);
        }
        return result;
    }
}

Could you please let me know if this is best practice to do in a web application ??

like image 791
Pawan Avatar asked Sep 06 '16 15:09

Pawan


1 Answers

There are host of ways you can handle it, so it all depends on whether your application server has that much resources (memory, threads etc.) to handle your implementation, so it makes you best person to decide on which approach to go.

As such it is not bad practice to spawn parallel threads for doing something if it is justified by design, but typically you should go with controlled threads.

Please note that whether you use newSingleThreadExecutor() or newFixedThreadPool(nThreads), under-the-hoods there will always be a ThreadPoolExecutor object created.

My recommendation will be to use seconds option in below list i.e. "Controlled number of threads", and in that specify max thread count as you see fir.

One thread for each request

In this approach one thread will be created for each incoming request from GUI, so if you are getting 10 requests for inserting/updating user then 10 threads will be spawned which will send emails.

Downside of this approach is that there is no control on number of threads so you can end with StackOverflowException or may be memory issue.

Please make sure to shutdown your executor service else you will end up wasting JVM resources.

// inside your getSalesUserData() method
ExecutorService emailExecutor = Executors.newSingleThreadExecutor();
        emailExecutor.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    SendEmailUtility.sendmail(emaildummy);
                } catch (IOException e) {
                    logger.error("failed", e);
                }
            }
        });
        emailExecutor.shutdown(); // it is very important to shutdown your non-singleton ExecutorService.

Controlled number of threads

In this approach, some pre-defined number of threads will be present and those will process your email sending requirement. In below example I am starting a thread pool with max of 10 threads, then I am using a LinkedBlockingQueue implementation so this will ensure that if there are more than 10 requests and currently all my 10 threads are busy then excess of requests will be queued and not lost, this is the advantage you get with LinkedBlockingQueue implementation of Queue.

You can initialize you singleton ThreadPoolExecutor upon application server start, if there are no requests then no threads will be present so it is safe to do so. In fact I use similar configuration for my prod application.

I am using time to live seconds as 1 seconds so if a thread is ideal in JVM for more than 1 seconds then it will die.

Please note that since same thread pool is used for processing all you requests, so it should be singleton and do not shutdown this thread pool else your tasks will never be executed.

// creating a thread pool with 10 threads, max alive time is 1 seconds, and linked blocking queue for unlimited queuing of requests.
        // if you want to process with 100 threads then replace both instances of 10 with 100, rest can remain same...
        // this should be a singleton
        ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10, 1, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());

        // inside your getSalesUserData() method
        executor.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    SendEmailUtility.sendmail(emaildummy);
                } catch (IOException e) {
                    logger.error("failed", e);
                }
            }
        });

Java's default cached thread pool

This approach is much like above, only that Java will initialize the ThreadPoolExecutor for you as ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());

Here max number of threads will be Integer.MAX_VALUE, so threads will be created as needed and time to live will be 60 seconds.

If you want to use this way then below is the way.

// this should be a singleton
        ExecutorService emailExecutor = Executors.newCachedThreadPool();

        // from you getSalesUserData() method
        emailExecutor.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    SendEmailUtility.sendmail(emaildummy);
                } catch (IOException e) {
                    logger.error("failed", e);
                }
            }
        });
like image 190
hagrawal Avatar answered Sep 29 '22 06:09

hagrawal