私は似たようなことをしなければならず、Charles Engelke が提案したように、SQS を使用しました。
メッセージの内容全体を SQS メッセージに入れることで、データベースを完全に排除しました。SQS メッセージで 64k に制限されているため、それが問題にならない限り、このアプローチは可能です。
メッセージをキューに入れるサンプル コードを次に示します。
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)));
}
}
次に、アプリで、キューをポーリングしてメッセージを処理するエグゼキューター サービスが必要です。
new ScheduledThreadPoolExecutor(1).scheduleAtFixedRate(sendEmails(), 0, 1, MINUTES)
アプリの終了時に、このエグゼキューターで shutdown() を呼び出すようにする必要があります。とにかく、この行は毎分電子メールを送信します。 sendEmails() は、この Runnable クラスのインスタンスを返します。
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;
}
}
データベースを使用している場合のこのアプローチのダウンサイズの 1 つは、メール送信ステップが HTTP 呼び出しであることです。この HTTP 呼び出しの後にロールバックするデータベース トランザクションがある場合、ビジネス プロセスは元に戻されますが、電子メールは送信されます。
思考の糧。