Skip to content

Commit 112624f

Browse files
Aleksey Kulaginmikemadisonweb
Aleksey Kulagin
authored andcommitted
Work with systemd
1 parent 2c5552a commit 112624f

File tree

6 files changed

+583
-51
lines changed

6 files changed

+583
-51
lines changed

Configuration.php

+4
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,10 @@ class Configuration extends Component
107107
'idle_timeout_exit_code' => null,
108108
'proceed_on_exception' => false,
109109
'deserializer' => 'unserialize',
110+
'systemd' => [
111+
'memory_limit' => 0,
112+
'workers' => 1
113+
],
110114
],
111115
],
112116
'logger' => [

README_v2.md

+245
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
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

Comments
 (0)