Email 来自数据库的SMS和电子邮件队列
我只是想讨论一下我面临的一种情况 我想向用户发送电子邮件-很多电子邮件-但如果我在应用程序运行时发送电子邮件,AWS SDK对电子邮件的速度很慢-糟糕的用户体验-至少对我的应用程序如此 因此,我计划在数据库中输入数据(电子邮件地址、要发送的内容、0),然后启动cron作业来读取表并开始发送电子邮件—一旦发送电子邮件—它将数据库行标记为1 我在某个地方读到一个错误的做法,导致数据库服务器过载 是的,我会使用智能cron,这样就不会有两个cron重叠,或者为偶数和奇数等设置一个cron。我也在寻找第三方替代方案,比如cronEmail 来自数据库的SMS和电子邮件队列,email,amazon-web-services,rds,Email,Amazon Web Services,Rds,我只是想讨论一下我面临的一种情况 我想向用户发送电子邮件-很多电子邮件-但如果我在应用程序运行时发送电子邮件,AWS SDK对电子邮件的速度很慢-糟糕的用户体验-至少对我的应用程序如此 因此,我计划在数据库中输入数据(电子邮件地址、要发送的内容、0),然后启动cron作业来读取表并开始发送电子邮件—一旦发送电子邮件—它将数据库行标记为1 我在某个地方读到一个错误的做法,导致数据库服务器过载 是的,我会使用智能cron,这样就不会有两个cron重叠,或者为偶数和奇数等设置一个cron。我也在寻找第
是否有人可以分享他们在类似情况下的经验等。我只想使用智能解决方案,而不仅仅是在数据库上投入大量资源和在事务上花费大量资金……我必须做一些类似的事情,并按照Charles Engelke的建议做——我使用了SQS 通过将整个消息内容放在SQS消息中,我完全消除了数据库。您仅限于,所以只要这不是一个问题,这种方法是可能的 下面是将消息排队的示例代码:
package com.softwareconfidence.bsp.sending;
import com.amazonaws.services.sqs.AmazonSQS;
import com.amazonaws.services.sqs.model.SendMessageRequest;
import com.googlecode.funclate.json.Json;
import java.util.HashMap;
import java.util.Map;
public class EmailQueuer {
private final AmazonSQS sqs;
private final String sendQueueUrl;
public EmailQueuer(AmazonSQS sqs,String sendQueueUrl) {
this.sqs = sqs;
this.sendQueueUrl = sendQueueUrl;
}
public void queue() {
Map<String,String> emailModel = new HashMap<String, String>(){{
put("from","me@me.com");
put("to","you@you.com");
put("cc","her@them.com");
put("subject","Greetings");
put("body","Hello World");
}};
sqs.sendMessage(new SendMessageRequest(sendQueueUrl, Json.toJson(emailModel)));
}
}
当应用程序退出时,您需要确保在此执行器上调用shutdown()。无论如何,此行每分钟都会发送电子邮件,其中sendEmails()返回此可运行类的一个实例:
package com.softwareconfidence.bsp.standalone.sending;
import com.amazonaws.services.simpleemail.AmazonSimpleEmailService;
import com.amazonaws.services.simpleemail.model.*;
import com.amazonaws.services.sqs.AmazonSQS;
import com.amazonaws.services.sqs.model.DeleteMessageRequest;
import com.amazonaws.services.sqs.model.ReceiveMessageRequest;
import com.amazonaws.services.sqs.model.ReceiveMessageResult;
import com.amazonaws.services.sqs.model.SendMessageRequest;
import com.googlecode.funclate.json.Json;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.List;
import java.util.Map;
public class FromSqsEmailer implements Runnable {
private final AmazonSQS sqs;
private final String sendQueueUrl;
private final String deadLetterQueueUrl;
private final AmazonSimpleEmailService emailService;
public FromSqsEmailer(AmazonSimpleEmailService emailService, String deadLetterQueueUrl, String sendQueueUrl, AmazonSQS sqs) {
this.emailService = emailService;
this.deadLetterQueueUrl = deadLetterQueueUrl;
this.sendQueueUrl = sendQueueUrl;
this.sqs = sqs;
}
public void run() {
int batchSize = 10;
int numberHandled;
do {
ReceiveMessageResult receiveMessageResult =
sqs.receiveMessage(new ReceiveMessageRequest(sendQueueUrl).withMaxNumberOfMessages(batchSize));
final List<com.amazonaws.services.sqs.model.Message> toSend = receiveMessageResult.getMessages();
for (com.amazonaws.services.sqs.model.Message message : toSend) {
SendEmailResult sendResult = sendMyEmail(Json.parse(message.getBody()));
if(sendResult != null) {
sqs.deleteMessage(new DeleteMessageRequest(sendQueueUrl, message.getReceiptHandle()));
}
}
numberHandled = toSend.size();
} while (numberHandled > 0);
}
private SendEmailResult sendMyEmail(Map<String, Object> emailModel) {
Destination to = new Destination()
.withToAddresses(get("to", emailModel))
.withCcAddresses(get("cc", emailModel));
try {
return emailService.sendEmail(new SendEmailRequest(get("from", emailModel), to, body(emailModel)));
} catch (Exception e){
StringWriter stackTrace = new StringWriter();
e.printStackTrace(new PrintWriter(stackTrace));
sqs.sendMessage(new SendMessageRequest(deadLetterQueueUrl, "while sending email " + stackTrace));
}
return null;
}
private String get(String propertyName, Map<String, Object> emailModel) {
return emailModel.get(propertyName).toString();
}
private Message body(Map<String, Object> emailModel) {
Message message = new Message().withSubject(new Content(get("subject", emailModel)));
Body body = new Body().withText(new Content(get("body", emailModel)));
message.setBody(body);
return message;
}
}
package com.softwareconsidence.bsp.standalone.sending;
导入com.amazonaws.services.simpleemail.AmazonSimpleEmailService;
导入com.amazonaws.services.simpleemail.model.*;
导入com.amazonaws.services.sqs.AmazonSQS;
导入com.amazonaws.services.sqs.model.DeleteMessageRequest;
导入com.amazonaws.services.sqs.model.ReceiveMessageRequest;
导入com.amazonaws.services.sqs.model.ReceiveMessageResult;
导入com.amazonaws.services.sqs.model.SendMessageRequest;
导入com.googlecode.funclate.json.json;
导入java.io.PrintWriter;
导入java.io.StringWriter;
导入java.util.List;
导入java.util.Map;
公共类FromSqsEmailer实现Runnable{
私人最终AmazonSQS sqs;
私有最终字符串sendQueueUrl;
私有最终字符串deadLetterQueueUrl;
专用最终AmazonSimpleEmailService电子邮件服务;
public FromSqsEmailer(AmazonSimpleEmailService emailService、String deadLetterQueueUrl、String sendQueueUrl、AmazonSQS sqs){
this.emailService=emailService;
this.deadLetterQueueUrl=deadLetterQueueUrl;
this.sendQueueUrl=sendQueueUrl;
this.sqs=sqs;
}
公开募捐{
int batchSize=10;
整数处理;
做{
ReceiveMessageResult ReceiveMessageResult=
sqs.receiveMessage(新的ReceiveMessageRequest(sendQueueUrl).withMaxNumberOfMessages(batchSize));
最终列表toSend=receiveMessageResult.getMessages();
for(com.amazonaws.services.sqs.model.Message消息:toSend){
SendEmailResult sendResult=sendMyEmail(Json.parse(message.getBody());
if(sendResult!=null){
sqs.deleteMessage(新的DeleteMessageRequest(sendQueueUrl,message.getReceiptHandle());
}
}
numberHandled=toSend.size();
}while(numberHandled>0);
}
私有SendEmailResult sendMyEmail(映射电子邮件模型){
目的地到=新目的地()
.WithToAddress(获取(“收件人”,emailModel))
。使用ccAddress(获取(“cc”,emailModel));
试一试{
返回emailService.sendmail(新的sendmailrequest(get(“from”,emailModel),to,body(emailModel));
}捕获(例外e){
StringWriter stackTrace=新StringWriter();
e、 printStackTrace(新的PrintWriter(stackTrace));
sqs.sendMessage(新的SendMessageRequest(deadLetterQueueUrl,“发送电子邮件时”+stackTrace));
}
返回null;
}
私有字符串获取(字符串propertyName,映射emailModel){
返回emailModel.get(propertyName.toString();
}
私人邮件正文(映射电子邮件模型){
Message Message=new Message().withSubject(新内容(get(“subject”,emailModel)));
Body Body=newbody().withText(新内容(get(“Body”,emailModel)));
信息.正文(正文);
返回消息;
}
}
如果您使用的是数据库,这种方法的一个缩编是电子邮件发送步骤是HTTP调用。如果您的数据库事务在此HTTP调用后回滚,则您的业务流程将撤消,但电子邮件将被发送
值得思考。谢谢你的详细回复,迈克。最后,我为我的应用程序实现了一个RESTAPI,使用安全的用户名+密码+密钥访问,并从第三方服务Iron.io运行它,该服务可以
www.example.com/rest/messages/format/json
它迭代并发送一个数组中收集状态的消息,然后将其发回
www.example.com/rest/messagesposted
我之所以采用这种方法,是因为我必须为超过30天的时间安排邮件
间隔90天,队列只保存消息14天左右
你发现了什么?这个问题似乎是为亚马逊的简单队列服务量身定做的。我研究发现,SQS可以解决这个问题,但即使我将模板发送到队列,然后运行cron读取消息,发送警报,然后删除这些消息-我仍然会用该消息的发送状态更新数据库。。。当然,在数据库上保存读取数据……更重要的是,您避免了数据库服务器的持续轮询。这就是你所建议的,人们觉得很讨厌的方面。您正在用“是否有任何消息?”查询轰炸数据库。此外,您不需要“运行cron”来读取消息。您有一个作业(或多个作业,取决于工作负载)一直在运行,它可以坐在队列中并侦听队列
www.example.com/rest/messagesposted