Отправляйте почту как можно транзакционнее - PullRequest
1 голос
/ 25 октября 2010

У меня есть простая программа, которая время от времени опрашивает таблицу БД и отправляет любую почту, которая указана в таблице, находится в состоянии ожидания (с использованием javax.mail). Когда письмо отправлено, я удаляю запись в БД.

Я заметил две потенциальные проблемы

  • Существует вероятность отправки почты, а затем происходит сбой, поэтому запись в БД все еще там. В следующий раз письмо будет отправлено снова.
  • Может быть много сообщений для отправки, поэтому я загружаю все ожидающие записи, отправляю их все, затем удаляю все записи в БД. Если некоторые / все письма отправлены, что-то не получается, и задание запускается снова, то это дважды рассылает много людей.

Это не спам-приложение, поэтому я хочу попытаться избежать отправки чего-либо дважды, а также убедиться, что я никогда не "потеряю" сообщение.

Это общая проблема, я уверен, что есть два физических ресурса, которые не могут участвовать в транзакции (БД + что-то еще), поэтому мне было интересно, какие подходы люди используют для уменьшения / устранения проблем в этом случае и / или общий случай.

Ответы [ 2 ]

1 голос
/ 25 октября 2010

У меня есть упрощенное решение вашей проблемы. Добавьте в БД поле с именем 'Pulled'

Проверьте Pulled = 0, затем извлеките данные, обновите 'Pulled' = 1 и отправьте электронное письмо. После отправки письма удалите запись.

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

Если 'Pulled' = 1 при первоначальной проверке, то вы знаете, что произошла ошибка, и вы должны принять решение о том, рискнуть ли вам повторно отправить электронное письмо или удалить его и рискнуть потерять его.

Вы точно знаете две вещи.

(1) Если 'Pulled' = 0, то электронное письмо не было отправлено.

(2) Если 'Pulled' = 1, то произошла ошибка в процессе отправки или удаления.

0 голосов
/ 25 октября 2010

Я бы определенно прочитал каждое письмо из базы данных по отдельности, чтобы избежать второй описанной вами проблемы.

Установите блокировку на строку базы данных (например, select for update) на случай, если одновременно выполняется несколько процессов (даже если вы не собираетесь этого делать, это может произойти случайно из-за неправильного развертывания, некоторого переключения при сбое, когда исходная служба еще работает, ..)

Отправьте письмо непосредственно перед вамивыполните commit для транзакции или отправьте сообщение в какую-нибудь асинхронную систему, например, через JMS.Но более простое решение - просто отправить электронное письмо непосредственно перед commit, если это возможно.Если что-то пошло не так с почтой, вы можете сделать откат.Если ничего не пошло не так, вряд ли что-то пойдет не так с commit, так что вы, вероятно, в порядке.

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

...