|
| 1 | +RabbitMQ Extension for Yii2 |
| 2 | +================== |
| 3 | + |
| 4 | +**Advanced usage** |
| 5 | + |
| 6 | +Для предотвращения потери сообщений при обмене с RabbitMq рекомендуется использовать расширенные настройки для настройки продюсеров и слушателей (воркеров). |
| 7 | + |
| 8 | +**Пример конфига:** |
| 9 | + |
| 10 | +``` |
| 11 | +<?php |
| 12 | +
|
| 13 | +use app\components\TestConsumer; |
| 14 | +use mikemadisonweb\rabbitmq\Configuration; |
| 15 | +use PhpAmqpLib\Connection\AMQPLazyConnection; |
| 16 | +use PhpAmqpLib\Connection\AMQPSSLConnection; |
| 17 | +
|
| 18 | +return [ |
| 19 | + 'class' => Configuration::class, |
| 20 | + 'connections' => [ |
| 21 | + [ |
| 22 | + 'type' => $_ENV['RABBITMQ_SSL'] ? AMQPSSLConnection::class : AMQPLazyConnection::class, |
| 23 | + 'host' => $_ENV['RABBITMQ_HOST'], |
| 24 | + 'port' => $_ENV['RABBITMQ_PORT'], |
| 25 | + 'user' => $_ENV['RABBITMQ_USER'], |
| 26 | + 'password' => $_ENV['RABBITMQ_PASSWD'], |
| 27 | + 'vhost' => $_ENV['RABBITMQ_VHOST'], |
| 28 | + 'ssl_context' => $_ENV['RABBITMQ_SSL'] ? [ |
| 29 | + 'capath' => null, |
| 30 | + 'cafile' => null, |
| 31 | + 'verify_peer' => false, |
| 32 | + ] : null |
| 33 | + ], |
| 34 | + ], |
| 35 | + 'exchanges' => [ |
| 36 | + [ |
| 37 | + 'name' => 'test_exchange', |
| 38 | + 'type' => 'direct' |
| 39 | + ], |
| 40 | + ], |
| 41 | + 'queues' => [ |
| 42 | + [ |
| 43 | + 'name' => 'test_queue', |
| 44 | + ], |
| 45 | + ], |
| 46 | + 'producers' => [ |
| 47 | + [ |
| 48 | + 'name' => 'test_producer', |
| 49 | + ], |
| 50 | + ], |
| 51 | + 'bindings' => [ |
| 52 | + [ |
| 53 | + 'queue' => 'test_queue', |
| 54 | + 'exchange' => 'test_exchange', |
| 55 | + ], |
| 56 | + ], |
| 57 | + 'consumers' => [ |
| 58 | + [ |
| 59 | + 'name' => 'test_consumer', |
| 60 | + 'callbacks' => [ |
| 61 | + 'test_queue' => TestConsumer::class |
| 62 | + ], |
| 63 | + 'systemd' => [ |
| 64 | + 'memory_limit' => 8, // mb |
| 65 | + 'workers' => 3 |
| 66 | + ], |
| 67 | + ], |
| 68 | + ], |
| 69 | +]; |
| 70 | +``` |
| 71 | + |
| 72 | +-------------------- |
| 73 | + |
| 74 | +**Настройка продюсеров** сводится к тому, что неотправленные сообщения сохраняются в таблице `rabbit_publish_error`, класс `\mikemadisonweb\rabbitmq\models\RabbitPublishError`, и отправляются, например, по крону. |
| 75 | + |
| 76 | +* в файле конфига консольного приложения в секции controllerMap прописываем namespace для миграций компонента |
| 77 | + |
| 78 | +``` |
| 79 | +... |
| 80 | +'controllerMap' => [ |
| 81 | + 'migrate' => [ |
| 82 | + 'class' => 'yii\console\controllers\MigrateController', |
| 83 | + 'migrationNamespaces' => [ |
| 84 | + 'mikemadisonweb\rabbitmq\migrations' |
| 85 | + ], |
| 86 | + ], |
| 87 | + ], |
| 88 | +... |
| 89 | +``` |
| 90 | + |
| 91 | +Выполняем `php yii migrate` |
| 92 | + |
| 93 | +* при вызове продюсера отлавливаем исключения, и пишем сообщения в БД, пример: |
| 94 | + |
| 95 | +``` |
| 96 | +public function actionPublish() |
| 97 | + { |
| 98 | + $producer = \Yii::$app->rabbitmq->getProducer('test_producer'); |
| 99 | + $data = [ |
| 100 | + 'counter' => 1, |
| 101 | + 'msg' => 'I\'am test publish' |
| 102 | + ]; |
| 103 | + while (true) { |
| 104 | + sleep(1); |
| 105 | + try { |
| 106 | + $producer->publish(json_encode($data), 'test_exchange'); |
| 107 | + $data['counter']++; |
| 108 | + } catch (\Exception $e) { |
| 109 | + $model_error = new RabbitPublishError(); |
| 110 | + $model_error->exchangeName = 'test_exchange'; |
| 111 | + $model_error->producerName = 'test_producer'; |
| 112 | + $model_error->msgBody = json_encode($data); |
| 113 | + $model_error->errorMsg = $e->getMessage(); |
| 114 | + $model_error->saveItem(); |
| 115 | + } |
| 116 | + } |
| 117 | + } |
| 118 | +``` |
| 119 | + |
| 120 | +* пример повторной отправки сохраненных сообщений |
| 121 | + |
| 122 | +``` |
| 123 | + public function actionRePublish() |
| 124 | + { |
| 125 | + $republish = new RabbitPublishError(); |
| 126 | + $republish->rePublish(); |
| 127 | + } |
| 128 | +``` |
| 129 | +Если повторное сообщение отправлено успешно, то запись удаляется, иначе поле counter увеличивается на 1. |
| 130 | + |
| 131 | +-------------- |
| 132 | + |
| 133 | +**Для расширенной настройки воркеров** необходимо запустить их в виде демонов с помощью systemd. |
| 134 | +Благодаря systemd мы можем решить две главные проблемы: |
| 135 | + |
| 136 | +1. Перезапуск воркеров при разрыве соединения |
| 137 | + |
| 138 | +2. Перезапуск воркеров при достижении memory limit |
| 139 | + |
| 140 | +Также с помощью systemd мы можем запускать несколько экземпляров воркеров для одной очереди |
| 141 | + |
| 142 | +* В конфиге rabbitmq, в секции `consumers` прописываем дополнительные настройки для systemd: для очереди `test_queue` запустить три воркера `test_consumer`, лимит памяти для каждого - 8 мб. |
| 143 | + |
| 144 | +``` |
| 145 | + 'consumers' => [ |
| 146 | + [ |
| 147 | + 'name' => 'test_consumer', |
| 148 | + 'callbacks' => [ |
| 149 | + 'test_queue' => TestConsumer::class |
| 150 | + ], |
| 151 | + 'systemd' => [ |
| 152 | + 'memory_limit' => 8, // mb |
| 153 | + 'workers' => 3 |
| 154 | + ], |
| 155 | + ], |
| 156 | + ], |
| 157 | +``` |
| 158 | + |
| 159 | +* Для автоматической генерации юнитов systemd рекомендуется использовать хелпер `\mikemadisonweb\rabbitmq\helpers\CreateUnitHelper` |
| 160 | + |
| 161 | +При объявлении хелпера необходимо определить следующие поля: |
| 162 | + |
| 163 | +``` |
| 164 | + /** @var string папка в которой будут созданы юниты, должна быть доступна на запись */ |
| 165 | + public $units_dir; |
| 166 | +
|
| 167 | + /** @var string имя пользователя от имени которого будут запускаться юниты */ |
| 168 | + public $user; |
| 169 | +
|
| 170 | + /** @var string имя группы для запуска юнитов */ |
| 171 | + public $group; |
| 172 | +
|
| 173 | + /** @var string директория с исполняемым файлом yii */ |
| 174 | + public $work_dir; |
| 175 | +``` |
| 176 | +Также в хелпере есть поле `example`, в нем хранится шаблон для генерации юнита. Рекомендуется его изучить и, при необходимости, переобъявить. Особое внимание секции `[Unit]` |
| 177 | + |
| 178 | +``` |
| 179 | + public $example = '[Unit] |
| 180 | +Description=%description% |
| 181 | +After=syslog.target |
| 182 | +After=network.target |
| 183 | +After=postgresql.service |
| 184 | +Requires=postgresql.service |
| 185 | +
|
| 186 | +[Service] |
| 187 | +Type=simple |
| 188 | +WorkingDirectory=%work_dir% |
| 189 | +
|
| 190 | +User=%user% |
| 191 | +Group=%group% |
| 192 | +
|
| 193 | +ExecStart=php %yii_path% rabbitmq/consume %name_consumer% %memory_limit% |
| 194 | +ExecReload=php %yii_path% rabbitmq/restart-consume %name_consumer% %memory_limit% |
| 195 | +TimeoutSec=3 |
| 196 | +Restart=always |
| 197 | +
|
| 198 | +[Install] |
| 199 | +WantedBy=multi-user.target'; |
| 200 | +``` |
| 201 | +Пример работы с хелпером, контроллер |
| 202 | + |
| 203 | +``` |
| 204 | +<?php |
| 205 | +
|
| 206 | +namespace app\commands; |
| 207 | +
|
| 208 | +use mikemadisonweb\rabbitmq\helpers\CreateUnitHelper; |
| 209 | +use yii\console\Controller; |
| 210 | +use Yii; |
| 211 | +
|
| 212 | +class CreateUnitsController extends Controller |
| 213 | +{ |
| 214 | + public function actionIndex() |
| 215 | + { |
| 216 | + $helper = new CreateUnitHelper( |
| 217 | + [ |
| 218 | + 'units_dir' => Yii::getAlias('@runtime/units'), |
| 219 | + 'work_dir' => Yii::getAlias('@app'), |
| 220 | + 'user' => 'vagrant', |
| 221 | + 'group' => 'vagrant', |
| 222 | + ] |
| 223 | + ); |
| 224 | +
|
| 225 | + $helper->create(); |
| 226 | + } |
| 227 | +} |
| 228 | +``` |
| 229 | + |
| 230 | +Не забываем запустить генерацию юнитов: `php yii create-units` |
| 231 | + |
| 232 | +* После генерации юнитов в папке c юнитами будет сгенерирован также баш скрипт exec.sh. При запуске, на вход могут быть переданы следующие команды: `copy | start | restart | status | delete`. Данный скрипт работает по маске со всеми сгенерированными юнитами. |
| 233 | + |
| 234 | +После первоначальной генерации юнитов, достаточно запустить команду `sh exec.sh copy` |
| 235 | + |
| 236 | +**Итак, для расширенной работы с воркерами** необходимо выполнить три шага |
| 237 | + |
| 238 | +1. Объявить параметры для systemd в конфиге RabbitMq |
| 239 | + |
| 240 | +2. Сгенерировать юниты для systemd |
| 241 | + |
| 242 | +3. Запустить воркеры как демоны под управлением systemd |
| 243 | + |
| 244 | +**Enjoy!** |
| 245 | + |
0 commit comments