Это моя рекомендация, и она использует базу данных для управления рабочей нагрузкой.
Я собираюсь использовать SQL Server в качестве примера, потому что это то, что я использовал сам.
То, что вы делаете, - это то, что вы создаете хранимую процедуру и / или назначаете таблицу как таблицу для исходящей электронной почты.Эта таблица, кроме той, которая вам нужна для отправки электронного письма, содержит следующие метаданные:
SendDate
IsSent
ErrorCount
Priority
В какой-то момент вам понадобится запустить поток или процесс, который выполняет фактическую работу, но какэто реализованный интересный бит.
С SQL Server вы можете написать запрос следующим образом:
DELCARE @now datetime; SET @now = GETDATE();
SELECT TOP (5) *
FROM OutgoingEmail WITH (ROWLOCK, READPAST, UPDLOCK)
WHERE SendDate < @now
AND IsSent = 0
AND ErrorCount < 5
ORDER BY Priority
;
READPAST можно указывать только в транзакциях, работающих с изоляцией READ COMMITTED или REPEATABLE READуровни.Вы будете устанавливать уровень изоляции при установлении нового соединения.
Теперь произойдет следующее: при использовании объекта SqlCommand
для создания DataReader
SQL Server заблокирует эти строки.Никакие другие экземпляры не смогут их получить.Это означает, что теперь у вас есть рабочая очередь для исходящей электронной почты.Однако важно помнить, что вы должны держать соединение открытым, пока выполняете обработку, иначе блокировка будет снята.
Несколько замечаний.
- Вы получаетекуча строк и вы их отправляете.Если у вас получилось установить бит IsSent
- Если вы потерпели крах (где-то возникло исключение), вы не откажетесь от электронного письма, в котором вы получите ErrorCount.Вы не удаляете это, вы просто увеличиваете счет.Это важно, потому что, если электронное письмо по какой-то причине содержало ввод (а не вызвано проблемой с сетевым подключением), оно могло бы продолжать сбой на отправлять клиентов , и это называется отравлением, и это предотвратит сбой плохих данныхВаши отправляют клиентов .Поэтому вы должны игнорировать электронную почту с высоким
ErrorCount
- . Вы также можете очистить скользящее расписание и переместить
SendDate
вперед, чтобы не пытаться повторять одно и то же время от времени. - Узким местом будет класс SmtpClient, но в зависимости от скорости, с которой вы хотите, чтобы ваши электронные письма отправлялись, вы можете ускорить столько агентов или потоков, сколько вам нужно, чтобы обрабатывать электронные письма параллельно.
- Приоритет будет гарантировать, чтоесли вам нужно отправить высокоприоритетное письмо, полная очередь не будет проблемой.например, если вы хотите отправить все свои электронные письма таким образом, отправка электронного письма с восстановлением пароля или регистрации не будет отложена только потому, что очередь заполнена, если она имеет более высокий приоритет.
Следует отметить, что при возникновении ошибок причина неизвестна, я видел случайную сетевую проблему, из-за которой электронные письма не отправлялись.При таком подходе обычно происходит то, что электронное письмо будет отправлено позднее, когда сетевое подключение или SMTP-сервер снова подключатся.Вы также можете иметь дополнительные метаданные, чтобы не отправлять более одного электронного письма пользователю, который пытается сбросить свой пароль (только потому, что по неизвестной причине электронные письма не отправляются прямо сейчас).
Последнийвещь.Возможно, вы захотите разделить таблицу на две или три идентичные таблицы.Причина этого заключается в том, что если вы хотите регистрировать отправленные электронные сообщения в течение определенного периода времени, вы не хотите, чтобы они мешали вашей высокопроизводительной очереди на отправку, в противном случае вы перемещаете их в отдельную таблицу, просто для ведения истории.Это то же самое, что и с ошибками: если электронные письма в конечном итоге приводят к ошибкам, вы можете захотеть занести их в журнал, и вы можете сделать это, переместив эти электронные письма из очереди отправки в очередь ошибок.