我们有一个大型应用程序,其中电子邮件作为所有Service
' @Transaction
的一部分发送。典型的Service
方法是
@Transactional(readOnly = false, rollbackFor = {Exception.class})
public String operation() {
//...
sendEmail(..); // will call JavaMailSender.send()
//...
if (condition) {
sendEmail(..); // will call JavaMailSender.send()
}
}
邮件服务器经常会出现问题,导致整个事务回滚。我们需要将电子邮件从事务中删除。将这些行逐个从所有Service
中删除,或者更改每个行的rollbackFor
注解是不可行的。由于现有应用程序的大小,我考虑将@Async
添加到自定义sendEmail
方法中,但在事务中这样做是not recommended,仍然会影响事务。
正在考虑的一些备选办法如下:
- 使用消息队列,例如Spring中的
RabbitMQ
。可以调整方法sendMail
,使其将带有参数的序列化邮件对象入队,侦听器将使用该消息队列。但这需要为MQ打开一个新端口 - 微服务:还需要打开新的URL和端口
- 一个每分钟运行一次的cron,它处理由只添加表行的
sendMail
输入的不完整行。
但是,有没有一个更简单、集中化的健壮解决方案不需要所有这些新的体系结构呢?实际的电子邮件必须在所有事务之外。
1条答案
按热度按时间pkwftd7m1#
TL;DR:
使用多态行为来更改发送电子邮件的类/接口,以执行不同的操作。例如,您可以将所有电子邮件添加到队列中,然后让不同的后台服务发送这些电子邮件。避开事务,因为不同的线程将发送电子邮件。
更长的答案
从长远来看,我强烈建议您考虑从交易中删除电子邮件代码。根据您的问题,这听起来很麻烦,但从长远来看,这会更好。一般来说,发送电子邮件不是交易的一部分。顺便说一句,这种改变不一定要一次发生。2在你的系统中做一张包含所有有这个“问题”的交易的票,并找到解决这个问题的方法。当人们有了一点开发时间,他们可能会选择列表中的一个方法并修复它。
在短期内,你可以实现email类的一个新实现,让这个类把你所有的邮件放在一个队列中,我们使用Spring Integration作为我们的队列框架,我们非常喜欢它。
在中期,始终使用排队策略来发送电子邮件。队列的阅读端应根据您的电子邮件服务器规则和容量,每秒/分钟/小时只发送一定数量的电子邮件。这样,如果您的应用程序出现问题,出于某种原因,它开始在一小时内发送我们的数十万封电子邮件,由于“随机”安全探测发生在您的休息日,你不会“Don“我没有接到部门主管的电话,”请“你解决问题。