spring 重构事务中当前的电子邮件调用,使其异步且不影响事务

3b6akqbq  于 2022-12-26  发布在  Spring
关注(0)|答案(1)|浏览(115)

我们有一个大型应用程序,其中电子邮件作为所有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输入的不完整行。

但是,有没有一个更简单、集中化的健壮解决方案不需要所有这些新的体系结构呢?实际的电子邮件必须在所有事务之外。

pkwftd7m

pkwftd7m1#

TL;DR:

使用多态行为来更改发送电子邮件的类/接口,以执行不同的操作。例如,您可以将所有电子邮件添加到队列中,然后让不同的后台服务发送这些电子邮件。避开事务,因为不同的线程将发送电子邮件。

更长的答案

从长远来看,我强烈建议您考虑从交易中删除电子邮件代码。根据您的问题,这听起来很麻烦,但从长远来看,这会更好。一般来说,发送电子邮件不是交易的一部分。顺便说一句,这种改变不一定要一次发生。2在你的系统中做一张包含所有有这个“问题”的交易的票,并找到解决这个问题的方法。当人们有了一点开发时间,他们可能会选择列表中的一个方法并修复它。
在短期内,你可以实现email类的一个新实现,让这个类把你所有的邮件放在一个队列中,我们使用Spring Integration作为我们的队列框架,我们非常喜欢它。
在中期,始终使用排队策略来发送电子邮件。队列的阅读端应根据您的电子邮件服务器规则和容量,每秒/分钟/小时只发送一定数量的电子邮件。这样,如果您的应用程序出现问题,出于某种原因,它开始在一小时内发送我们的数十万封电子邮件,由于“随机”安全探测发生在您的休息日,你不会“Don“我没有接到部门主管的电话,”请“你解决问题。

相关问题