在可重试操作中发送电子邮件(或任何消息)一次,且仅发送一次

Send an email (or any message) once and only once inside a retryable operation

提问人:Max 提问时间:4/15/2016 更新时间:4/15/2016 访问量:722

问:

我有一个程序正在向用户的信用卡收费。该卡通过第三方 API 收费。当我收到来自第三方 API 的响应时,我会更新用户余额的内部表示形式。更新用户余额后,将通过电子邮件向用户发送收据。

在为用户卡充电和更新其余额的内部表示之间,发生某些服务器错误(例如意外断电)的可能性很小。为了防止这种情况,我已将整个支付过程设置为幂等,因此可以在不向用户重复收费的情况下重试,但肯定会更新用户的内部余额。唯一的问题是发送收据。没有办法(我能想到的)使此操作具有幂等性。目前,我只发送一封余额更新实际上更改了任何内容的电子邮件,但当然,服务器可能会在余额更新和发送收据之间出现故障,从而导致收据永远不会发送的情况。人们通常如何解决这个问题?

我之所以将这个问题标记为,是因为这似乎是发送消息的普遍问题,但我正在使用 Java 和 AWS 的简单电子邮件服务,因此使用这些技术获得答案会很棒。language-agnostic

java 电子邮件 amazon-web-services 与语言无关

评论

0赞 SpringLearner 4/15/2016
我认为您在用户表 isMailSent 中创建了一个位类型的列。当您需要发送电子邮件时,请检查 isMailSent 列。如果是,则不要发送否则发送
0赞 Max 4/15/2016
@SpringLearner 更新数据库和发送电子邮件之间可能存在故障,因此我认为您的解决方案无法保证单次交付。
0赞 SpringLearner 4/15/2016
你不使用交易吗?

答:

-1赞 Theresa Forster 4/15/2016 #1

当我们之前这样做时,我们在发送通知时设置的对象中使用了一个标志,这样如果为该事务/ID 设置了该标志,循环就不会发送电子邮件

评论

1赞 Max 4/15/2016
但是,您如何保证设置标志/发送电子邮件是原子操作?也就是说,您如何保证在设置标志和发送电子邮件之间永远不会出现故障?
0赞 Theresa Forster 4/15/2016
该方法被设置为同步,但这并不能保证,电子邮件被发送并且没有设置标志的可能性很小,不值得尝试修复, - 您在发送后设置标志,以便您知道电子邮件是否已成功发送。另一方面,如果您只是将其放入数据库并具有不同的进程,发送电子邮件并设置标志,那么它可以作为事务完成并得到原子保证
1赞 Max 4/15/2016
我不认为这能保证幂等性。发送电子邮件是不受任何数据库控制的副作用,因此涉及电子邮件的交易不可能是幂等的(据我所知)。
0赞 Tony Dinh 8/16/2019
@Max 关于幂等电子邮件传递有什么新发现吗?我有同样的问题。
0赞 nitsujri 5/27/2021
一种可能的方法是访问您控制的电子邮件/服务器,然后检查数据库标志与该电子邮件服务器之间的一致性。如果其中任何一方说它已发送,请不要发送。bcc: