рассылка почты с использованием queue

Общие вопросы по использованию второй версии фреймворка. Если не знаете как что-то сделать и это про Yii 2, вам сюда.
Ответить
zemlia-zemlia
Сообщения: 35
Зарегистрирован: 2019.12.05, 20:03

рассылка почты с использованием queue

Сообщение zemlia-zemlia »

Здравствуйте, объясните, пожалуйста, в общих чертах,
как ПРАВИЛЬНО сделать массовую рассылку.
Надо отправлять по 100 писем, потом перерыв например 30 сек.
потом дальше.(задается параметром)
В данный момент у меня так.
Выбираем какой роли юзеров слать, пишем текст, тему,
нажимаем создать. Это простой CRUD
Потом нажимаем кнопку сформировать рассылку (там 60к писем)
дальше в контроллере запускается

Код: Выделить всё

   Yii::$app->queue->push(new \app\models\NewsLettersCreateJob([
            'newsLetterId' => $id,
            'newsLetterCount' => Yii::$app->params['newsLetterCount'],
             'newsLetterDelay' => Yii::$app->params['newsLetterDelay']

        ]));

        $queue = Yii::$app->queue;
        $queue->run(false);
этот Job там чего то делает,
и в цикле создает еще очереди

Код: Выделить всё

  foreach ($users as $user){
      // тут всяко разно делает
            if($i % $this->newsLetterCount == 0 || count($users) < $this->newsLetterCount){
                \Yii::$app->db->createCommand()->batchInsert(NewsletterQuene::tableName(), NewsletterQuene::attributesName(),  $insert)->execute();
 // раз в 100 писем создает задачу
                $insert = [];
                \Yii::$app->queue->delay($this->newsLetterDelay + ($this->newsLetterDelay * ($i / 100)))->push(new NewsLetterJob([
                    'newsLetterId' => $model->id,
                ]));
            }
         } // end loop
но эти задачи начинают выполняться сразу после создания.
для того, что бы как то работало, пришлось пока delay устанавливать рекурсивно
Я понимаю, что это все костыль на костыле.

Не могли бы вы объяснить, пожалуйста, как это правильно надо делать.
По ТЗ рассылка должна создаваться одной кнопкой, после создания
(как то получать статус что отработал Джоб по созданию) должна
появляться вторая кнопка отправить рассылку,
и по ее нажатию должна уже запускаться очередь по отправке.
И как решить вопрос с таймаутом между джобами по рассылке.
Я предполагаю, что каналы какие то надо использовать, но вообще не втыкаю что это.
и да. драйвер queue - db
само расширение - yiisoft/yii2-queue

Заранее спасибо
zemlia-zemlia
Сообщения: 35
Зарегистрирован: 2019.12.05, 20:03

Re: рассылка почты с использованием queue

Сообщение zemlia-zemlia »

И да, не вариант что то делать из консоли. Надо чтоб кнопкой в вэбе все это запускалось
Аватара пользователя
yiijeka
Сообщения: 3103
Зарегистрирован: 2012.01.28, 09:14
Откуда: Беларусь
Контактная информация:

Re: рассылка почты с использованием queue

Сообщение yiijeka »

Всё очень просто - после отправки письма увеличиваем счётчик на 1 и меняем статус письма на "отправлено".
Как только счётчик достигает 100, фиксируем время отправки письма.
При отправке почты проверяем счётчик, если он >=100, то по метке времени проверяем прошло ли 30 секунд. Если да, то сбрасываем счётчик на 0 и продолжаем отправлять письма. Если не прошло 30 секунд, то письмо не отправляем - оставляем у него статус "не отправлено" и отправляем его опять в очередь.
yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: рассылка почты с использованием queue

Сообщение yiiliveext »

Добавляете в таблицу рассылок поле статус, в задании формируете письма для рассылки и пишете их в базу, по окончании ставите статус "сформировано". На клиенте по нажатию на кнопку сформировать отсылаете c помощью js запрос на формирование на сервер и устанавливаете таймер, в котором опрашивается бекенд на предмет окончания формирования, когда сформировано, показываете кнопку отправить и удаляете таймер. Это вариант без вебсокетов.
zemlia-zemlia
Сообщения: 35
Зарегистрирован: 2019.12.05, 20:03

Re: рассылка почты с использованием queue

Сообщение zemlia-zemlia »

Да это все понятно. Статусы и прочее. У меня идея не из одной задачи отправлять 60к писем, а при формировании списка рассылки сформировать очередь задач, которая будет уже непосредственно отправлять по 100 писем.
вот в том коде что я выше приводил, как раз и формируется такая очередь.
из таких вот задач:

Код: Выделить всё

class NewsLetterJob extends BaseObject implements \yii\queue\JobInterface
{

    public $newsLetterId;

    public function execute($queue)
    {
        $newsLetter = Newsletter::find()->where(['id' => $this->newsLetterId])->one();
        $mails  = NewsletterQuene::find()->where(['status' => 1])->andWhere(['newsletter_id' => $this->newsLetterId])->limit(\Yii::$app->params['newsLetterCount'])->all();
        $changeStatus = [];
        foreach ($mails as $mail){
            \Yii::$app->mailer->compose(
                'newsletter',
                [
                    'content' => $newsLetter->message,
                    'name' => $mail->user_name
                ]
            )
                ->setFrom(\Yii::$app->params['fromEmail'])
                ->setTo($mail->email)
                ->setSubject($newsLetter->subject)
                ->send();

            $changeStatus[] = $mail->id;
        }

        NewsletterQuene::updateAll(['status' => 2], ['in', 'id', $changeStatus]);
        $newsLetter->total_success = $newsLetter->total_success + count($changeStatus);
        $newsLetter->status = 3;
        $newsLetter->update();


    }
}
вот их формируется как раз 600 штук (по 1 на 100 писем)
сейчас то все работает, да немного не так, как хотелось.
Все эти задачи запускаются сразу же после формирования,
а хотелось бы что бы по 1 кнопке запустилась задача NewsLettersCreateJob
(она выше в коде приведена не полностью, только цикл, в котором задачи пушатся, остально не существенно.)
потом статус узнавался (ну статус я понял, да на аяксе опрос Yii :: $ app -> queue -> isDone ( $ id );
и если ок, покажу кнопку, а потом?
как сделать, чтоб те 600 задач, которые сформировались, запускались через 30 секунд одна за другой?
и как указать тайм аут?
Из вэба аяксом дергать не вариант, надо со страницы уцти и заниматься своими делами, 60к писем не быстро отправятся.
ТО есть резюмирую.
1 как сделать, что бы задачи запустились из вэба и уйти со страницы.
(только не $queue->run(true);
потому что вешает сайт наглухо, только апач перезапускать помогает.
2. как сделать очередь задач, которые будут выполняться через равные промежутки времени и запустить ее из вэба.
yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: рассылка почты с использованием queue

Сообщение yiiliveext »

zemlia-zemlia писал(а): 2019.12.26, 16:34 потом статус узнавался (ну статус я понял, да на аяксе опрос Yii :: $ app -> queue -> isDone ( $ id );
и если ок, покажу кнопку, а потом?
как сделать, чтоб те 600 задач, которые сформировались, запускались через 30 секунд одна за другой?
и как указать тайм аут?
Из вэба аяксом дергать не вариант, надо со страницы уцти и заниматься своими делами, 60к писем не быстро отправятся.
ТО есть резюмирую.
1 как сделать, что бы задачи запустились из вэба и уйти со страницы.
(только не $queue->run(true);
потому что вешает сайт наглухо, только апач перезапускать помогает.
2. как сделать очередь задач, которые будут выполняться через равные промежутки времени и запустить ее из вэба.
Очередь работает из крона или как демон.
Показали кнопку Отправить, по клику послали запрос на бек, он сформировал 600 задач и поставил в очередь.
zemlia-zemlia
Сообщения: 35
Зарегистрирован: 2019.12.05, 20:03

Re: рассылка почты с использованием queue

Сообщение zemlia-zemlia »

Ну а как в очереди сделать таймаут между очередями
yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: рассылка почты с использованием queue

Сообщение yiiliveext »

Одно письмо - одна задача. По счетчику вам выше объяснили.
Ответить