Yii2 kolejka maili

Problem:

Kiedy dodajemy ogłoszenie dla studentów, wybieramy grupę studentów. Zdarza się, że liczba wybranych jest powyżej 2000-2500. Wtedy, mimo dużego timeout'u wykonywania skryptu, serwer zwróci do przeglądarki przekroczenie czasu wykonywania. Poza tym użytkownik musi czekać bez ządnych komunikatów na odpowiedź serwera - powstaje wrażenie, że "coś się zawiesiło"

yii2 mailer queue

Mechanizm kolejkowania składa się z serwisu CRON oraz kodu PHP dającego dostęp do zarządzania tzw. jobami :)

Instalujemy w yii2 moduł koleiki jopbów i korzystający z niego Mailer:

composer require --prefer-dist shaqman/yii2-queue-mailer
<code>composer require --prefer-dist yiisoft/yii2-queue</code>

Konfiguracja opisana w dokumentacji yiisoft/yii2-queue: https://github.com/yiisoft/yii2-queue mówi nam, że możemy podpiąć bazę danych z otworzoną tabelą dla przechowywania info o zadaniach. Próbowałem użyć MySQL, niestety bezskutecznie. Występował problem z Mutextem:

Exception 'yii\base\InvalidConfigException' with message 'In order to use MysqlMutex connection must be configured to use MySQL database.'

Nie udało mi się tego problemu rozwiązać. Ponieważ na serwerze mam REDIS użyłem konfiguracji w pliku config/web.php:

components' => [
        'redis' => [
            'class' => \yii\redis\Connection::class,
            // ...
            // retry connecting after connection has timed out
            // yiisoft/yii2-redis >=2.0.7 is required for this.
            'retries' => 1,
        ],
        'queue' => [
            'class' => \yii\queue\redis\Queue::class,
            'redis' => 'redis', // Redis connection component or its config
            'channel' => 'queue', // Queue channel key
        ],

mój Mailer jest skonfigurowany tak, że używam serwera SMTP na innym serwerze (nie na tym samy co strona w yii2), konfiguracja dla queuemailer wygląda tak:

  [
    'class' => \shaqman\mailer\queuemailer\Mailer::class,
    'queue' => 'queue',
    'syncMailer' => [ 
        'class' => 'yii\swiftmailer\Mailer',
        'useFileTransport' => false, 
        'transport' => [
            'class' => 'Swift_SmtpTransport',
            'host' => '*',
            'username' => '*',
            'password' => '*',
            'port' => '25',
            'encryption' => 'tls',
        ],
    ],
];

Oczywiście * zamienić należy na serwer, login, hasło.

Następny krok to konfiguracja dla polecenia z konsoli. Należy dodać:

  • w bootstrapie wczytywanie queue,
  • w komponentach dodać konfigurację redis i queue.

Zmieniam mój confog/console.php tak:

// ..
<span class="redactor-invisible-space">'bootstrap' => [
        'queue',
        'log',
    ],
// ..</span>
'components' => [
        // ...
        'redis' => [
            'class' => \yii\redis\Connection::class,
            'retries' => 1,
        ],
<span class="redactor-invisible-space">        'queue' => [
            'class' => \yii\queue\redis\Queue::class,
            'redis' => 'redis', // Redis connection component or its config
            'channel' => 'queue', // Queue channel key
        ],</span>
        // ...


Teraz wszytko testuję poleceniem w terminalu na serwerze z Yii2:

/var/www/html/firma/yii queue/info

dostaje wynik:

Jobs
- waiting: 0
- delayed: 0
- reserved: 0
- done: 0

Oznacza to, że wszystko działa OK!

Teraz dodaje do crona polecenie, które uruchamiam co 10 minut jako root. W tym celu dodaje do /etc/crontab:

*/10 * * * * root /var/www/html/firma/yii queue/run


Z oprogramowaniem yii2-mailqueue jest jeden problem: maler->send() zwraca numer zadania dodanego do kolejki zadań a nie true. Należy więc zmienić funkcję Powiadom w modelu Osoba. U mnie wygląda to tak:

public function Powiadom($temat, $tresc, $sms = false, $tresc_sms = false) { 
// ... 
$job_id = Yii::$app->mailer
 ->compose('powiadomienie', ['tresc' => $tresc])
 ->setFrom($email_nadawcy)
 ->setTo($emiale_odbiorcy)
 ->setSubject($temat)
 ->send();
 $message = (is_numeric($job_id)) ? "Dodano email do kolejki wysyłania emaili pod numerem: " . $job_id . PHP_EOL :
 Alert::widget([
 'options' => ['class' => 'alert-danger'],
 'body' => "NIE DODANO WIADOMOŚCI DO KOLEJKI EMAILI!!!"
 ]);
// ...
<span class="redactor-invisible-space">return $message;
    }</span>

Ostateczny test: Maile dochodzą - jest OK :)

uff... trza mi kawy :)

Dziękuję za lekturę