Фоновая Рассылка Писем

Есть компании и клиенты. Клиент создает заявку и уведомление должно отправиться всем компаниям. Т.к. компаний много, то надо выполнять это в фоновом режиме. Как это реализовать на yii?

Как я понял можно создать некую команду в Yii и с помощью Cron ее запускать. Но как это сделать прямо из php скрипта? Командой exec? Чтобы в контроллере при обработке заявки и добавлении ее в базу автоматически запускался скрипт рассылки. Или я вообще не в том направлении думаю?

Что бы создать консольную команду, которую можно будет запустить кроном, достаточно создать файлик в "protected\commands\" по инструкции Команда консоли

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

Для рассылок я обычно отвожу отдельную табличку или ключ в редисе - очередь. Приложение добавляет в эту очередь задания, а консольная команда обрабатывает эту очередь отправляя сообщения. Т.е. консольная команда запускается каждую минуту, если очередь сообщений не пустая, то начинает их отправлять. Может такая схема подойдет и вам, или кто то предложит более удобную.

Обращаю внимание, что необходимо будет предусмотреть защиту от запуска двух консольных команд. Что если команда не успеет отправить все сообщения за минуту и запустится еще одна? Ни в коем случае не должно произойти повторная отправка, поэтому получив адрес отправителя из очереди, нужно немедленно его удалить из неё, или поместить как обработанного.

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

Да про создание читал. Там вроде есть такой прием как ignore_user_abort для exec, позволяет выполнять команду в фоне.

Если выполняется одна команда то следующую уже не запустить? Или может параллельно выполняться одна и та же команда несколькики экземплярами. Например если у меня одновременно создадут две заявки, будет вызов двух таких команд, не перекроют ли они одна другую?

По схеме через очередь. А можно же наверно делать так чтобы эта команда проверяла очередь не только каждую минуту но и по какому нибудь сигналу?

И еще вопрос как сделать запуск такой команды каждую минуту? Как контролировать ее работу(вдруг там проблемы с сервером хостинга или еще что-то)? С консольными командами в применении к сайтам просто никогда не работал, поэтому возникают такие вопросы.

Тогда запускайте через exec и не беспокойтесь особо про очередь.

Почему нет? Консольная команда это процесс РНР которому выполняет определенный php файл. Главное что бы этот скрипт был потокобезопасным. У вас он наверное такое и получится, но все же приведу пример, что бы понимали чего следует избегать.

Например есть в таблице 100 записей с адресами и консольная команда отправляет каждому email и когда всем отправит- удаляет записи из таблицы. Если запустить вторую команду, когда первая уже разослала половине адресатов но еще не удалила, то вторая команда вычитает 100 адресов и начнет рассылать, в итоге всем уйдет по 2 сообщения.

Команда запускается просто, входите в папку protected и запускаете yiic <имя команды>


cd /projects/my_app/protected & yiic MyConsoleApp

можете настроить cron что бы запускал эту программу каждую минуту к примеру (чаще минуты cron не в состоянии)

В такой постановке вопроса, ничего не могу ответить.

Очевидно только через лог. Пишите лог в своей команде (Журналирование Yii) а потом смотрите лог.

Cron еще отсылает админу на мыло то, что возвращает запущенные им команды (не знаю, по дефолту это или настраивать надо), но на моем проекте это было настроено, я тогда писал хелпер, что бы сообщение выводилось в консоль (а значит потом отправлялось кроном на мыло) и в журнал Yii

Да и надо паузу между появлением заявки на сайте и отправкой цепочки писем сделать минимальной, потому что скорость реакции на появление заявки очень важна. Именно поэтому и возникала мысль запуска прямо из контроллера

Значит запускайте из контроллера.

Я хочу сделать чтобы каждая такая команда выполняла рассылку по определенной заявке, id которой передается команде в качестве аргумента. Команда уже и базы достает email по которым нужно сделать рассылку и в цикле выполняет эту рассылку. Тут я думаю описанной вами проблемы не возникнет.

Как по мне, то вы уже немного запутали. Понятно, что из БД достаёт! Но в каком цикле?

А как я буду делать рассылку письма на несколько адресов в таком варианте?