Как я могу избежать отправки дубликатов электронных писем, когда я фиксирую действие отправки электронной почты после отправки электронной почты?

Когда пользователь регистрируется на моем веб-сайте, я создаю запись пользователя в базе данных с email_sent = 'NO'. Затем у меня есть задание cron, которое отправляет приветственные письма каждые несколько минут. Он выбирает все записи пользователей, где email_sent = 'NO', и отправляет приветственное письмо.

Если электронное письмо успешно отправлено, оно обновляет запись пользователя на email_sent='YES'. Мой вопрос в том, как я могу избежать сценария, когда электронное письмо отправляется успешно, но обновление записи пользователя не выполняется, и в следующий раз, когда задание cron запускается, оно отправляет дубликат электронной почты. Даже если бы я использовал транзакцию базы данных и обновил запись перед отправкой электронного письма, но затем зафиксировал ее, если фиксация не удалась, у меня была бы та же ситуация с отправкой дубликатов электронных писем.

Альтернативой является обновление записи до email_sent='YES' и немедленная фиксация, а затем попытка отправить электронное письмо. Но если электронная почта не отправляется, электронная почта не отправляется.

Есть ли способ гарантировать, что электронное письмо будет отправлено ровно один раз? Я понимаю, что доставка электронной почты может в конечном итоге завершиться неудачей из-за ряда внешних факторов, но я просто хочу убедиться, что мой SMTP-сервер успешно отправляет ее ровно один раз.


person william    schedule 31.07.2012    source источник
comment
Почему не удается обновить запись пользователя? Решите это, и вы решили свою проблему.   -  person Robert Harvey    schedule 01.08.2012
comment
Какую СУБД вы используете, Oracle, SQL-Server, MySQL и т. д.? Вполне вероятно, что будет что-то конкретное для базы данных, что может помочь.   -  person Ben    schedule 01.08.2012
comment
В дополнение к комментарию Роберта Харви: если ваши коммиты не увенчались успехом при обновлении отправленной записи, мало что можно сделать для предотвращения дублирования. Если cron использует значение в базе данных, это значение должно быть надежно обновлено. В противном случае вам придется разрабатывать все более сложные способы обработки противоречивых данных.   -  person Farray    schedule 01.08.2012
comment
В настоящее время это не выходит из строя, но я параноик и беспокоюсь, что это может произойти.   -  person william    schedule 01.08.2012
comment
@user1566921 user1566921 Можете ли вы настроить журнал, чтобы увидеть, как часто отправляются повторяющиеся электронные письма? Затем вы можете увидеть, превышает ли фактическая частота дублирования {AcceptableRate}.   -  person Farray    schedule 01.08.2012


Ответы (1)


В вашем комментарии говорится, что коммиты не терпят неудачу, поэтому вы можете беспокоиться о ветре.

Держите транзакцию как можно меньше и не допускайте ее сбоя в зависимости от того, какой способ более приемлем в вашей системе...

BeginTransaction;
LookupRecord;

SendMail;

if(SentSuccessfully)
{
    UpdateRecord(Sent=True);
    CommitTransaction;
}
else
{
    RollbackTransaction;
}

В качестве альтернативы вы можете сделать это с большей сложностью и без транзакции вокруг функции электронной почты, но я не вижу этого лучше:

BeginTransaction;
LookupRecord;
UpdateRecord(Sent=True);
CommitTransaction;

SendMail;

if(!SentSuccessfully)
{
    UpdateRecord(Sent=False);
}

В любом случае, если у вас есть ошибки и правильное значение не зафиксировано в базе данных, вы мало что можете сделать, чтобы избежать этого, не вводя (потенциально ненужных) сложностей. Вы действительно должны сосредоточиться на том, чтобы сделать обновление и транзакцию надежной, чтобы она не переставала обновляться.

person Farray    schedule 31.07.2012