简体   繁体   中英

Transaction and sending an email

Considering the common use case of a user creating a new account on a web application and the application sending a confirmation email to the user's address. From what I've seen, this is typically implemented in one of 3 ways:

  1. The web controller calls a service method, which creates the user account and sends the email, both within a single transaction.
  2. The web controller calls a service method (with tx propagation = never), which invokes a 1st method on itself to create the user account within a transaction, and then invokes a 2nd method on itself to send the email.
  3. The web controller calls a 1st service method, which creates the user account within a transaction, then a 2nd service method that sends the email.

The 1st approach is simple and straightforward, but there is a risk that the transaction is rolled back after the email was sent, thereby making the email invalid. The 2nd approach is more complicated, but it guarantees that the email is sent only if user creation has actually succeeded. The 3rd approach is simple but burdens the web layer with business logic that it shouldn't need to know.

Isn't there a simpler approach, maybe AOP-driven, that guarantees that the email will be sent only if the user creation transaction actually succeeded? Am I paranoid in thinking that the 1st approach could fail?

We're using a Java EE + Spring stack and are willing to integrate additional APIs (AOP? Spring Integration?) to achieve this.

Cheers!

Another option I am currently using to solve this problem:

http://download.oracle.com/javaee/6/api/javax/transaction/Synchronization.html

To send emails, it is recommanded to use a Queue and schedule the emails to be send like every 5 or 15 minutes. The queue will be stored in the database, therefor within the transaction. Then schedule a procedure to send email from that Queue at regular interval.

Its the only way i found to make sure the email is sent only when the transaction is coompleted and commited, since emails by definition are not tied to any kind of database transactions.

Queuing with database table and run scheduling program with Quartz or something like whould be reasonable and easy to implement.

It's also good idea to use RabbitMQ for those feature development. RabbitMQ is quite easy to configure and can be used for the most of the case for publish/subscribe interworking betwen systems even though you may need to implement application level ack and small apps that subscribes messages from RabbitMQ and send email through SMTP.

It may sounds overkill, but you can use this #2 solution for every system that requires email send in the future. You can still use database queue based model for this, but will use expensive database cpu/resources for to send emmail.

I would add a lightweight JMS layer like ActiveMQ for the email, it is pretty easy to setup and integrates (and even embeds) with Spring. Then you have

1) User creation transaction & send of JMS message happening in 1 transaction. If either fails you're still in a good state (both commit or both rollback and you present an error to the user)

2) If the JMS consumer fails to send the email you can setup the JMS queue to retry a few times and you'll have a better solution for managing transient problems with your email system.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM