Події життєвого циклу
Обробка кожного RPC-запиту проходить через події Symfony EventDispatcher. Підписавшись на них, можна додати аудит, метрики, трасування, змінити аргументи методу чи підмінити помилку — не змінюючи процедури.
Лістенери втручаються в роботу сервера. Перш ніж змінювати дані чи зупиняти поширення події, прочитайте сторінку відповідної події: для кожної описано, що можна змінювати безпечно, а що ні.
Порядок подій
Для звичайного запиту з id:
rpc.request
└─ (кеш: якщо є відповідь у #[RPC\Cache] — далі нічого не генерується)
rpc.pre_execute ← валідація, конвертація параметрів, #[RPC\Lock], виклик методу
├─ успіх: rpc.pre_response → rpc.post_execute
└─ помилка: rpc.error → rpc.pre_response
── відповідь відправлено клієнту ──
rpc.post_response ← CacheRelation, notifications, $rpc.callback
Для notifications і $rpc.callback при прийомі генеруються лише rpc.request і rpc.pre_response з відповіддю-заглушкою, а сам метод виконується в rpc.post_response — зі своїми rpc.pre_execute, rpc.pre_response, rpc.post_execute. Повний опис — на сторінці Життєвий цикл.
Перелік подій
Назви — константи Ufo\JsonRpcBundle\EventDrivenModel\Events\RpcEvent, класи — у тому самому просторі імен.
| Подія | Клас | Коли |
|---|---|---|
rpc.request |
RpcRequestEvent |
Запит прийнято, до перевірки кешу |
rpc.pre_execute |
RpcPreExecuteEvent |
Перед викликом методу; тут же виконується сам метод |
rpc.post_execute |
RpcPostExecuteEvent |
Метод успішно виконано |
rpc.pre_response |
RpcPreResponseEvent |
Відповідь сформовано |
rpc.post_response |
RpcPostResponseEvent |
Відповідь відправлено клієнту |
rpc.error |
RpcErrorEvent |
Помилка під час виконання |
rpc.async_output |
RpcAsyncOutputEvent |
Дочірній процес batch повернув результат |
rpc.async_request |
RpcAsyncRequestEvent |
Оголошена, але бандл її не генерує |
Підписка
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
use Ufo\JsonRpcBundle\EventDrivenModel\Events\RpcEvent;
use Ufo\JsonRpcBundle\EventDrivenModel\Events\RpcPostResponseEvent;
#[AsEventListener(RpcEvent::POST_RESPONSE)]
final class AuditListener
{
public function __invoke(RpcPostResponseEvent $event): void
{
// $event->rpcRequest->getMethod(), $event->response ...
}
}
Пріоритет задається в атрибуті: #[AsEventListener(RpcEvent::PRE_EXECUTE, priority: 500)]. Більший пріоритет — раніше. Пріоритети вбудованих лістенерів наведено на сторінці кожної події: від них залежить, що ваш лістенер побачить і чи взагалі буде викликаний.
Загальні правила
- Властивості подій публічні й не readonly, але присвоєння нового значення діє не завжди — див. сторінку події.
stopPropagation()зупиняє не лише ваших сусідів, а й вбудовані лістенери з нижчим пріоритетом. Наrpc.pre_execute,rpc.pre_responseіrpc.errorце може залишити запит без відповіді — не зупиняйте ці події, якщо не формуєте відповідь самі.- Виняток з лістенера перетворюється на відповідь з помилкою. В одиночному HTTP-запиті він не проходить через
rpc.error(див. Актуальні помилки). - Кешована відповідь (
#[RPC\Cache]) повертається без подій виконання: післяrpc.requestнічого не генерується.
Контекст усередині лістенера
| Що потрібно | Звідки взяти |
|---|---|
Метод, параметри, id |
$event->rpcRequest->getMethod(), getParams() (без $rpc), getId() |
Спеціальні параметри $rpc |
$event->rpcRequest->getRpcParams() — getTimeout(), hasCallback(), getRayId(), ignoreCache |
| Notification чи ні | $event->rpcRequest instanceof Ufo\RpcObject\RpcNotificationRequest |
| Версія API | $event->rpcRequest->apiVersion |
| Група API | сервіс Ufo\JsonRpcBundle\Server\ApiGroupContext: getGroup() |
| HTTP-запит | сервіс Ufo\JsonRpcBundle\Server\RequestPrepare\RequestCarrier: getCarrier(), якщо це IRpcHttpCarrier — getHttpRequest() |
| Токен | сервіс IRpcSecurity: getTokenHolder()->getToken() |
| Попередні події цього запиту | сервіс RpcEventFactory: getEvent(Клас::class), getEvents(Клас::class) |
Власні події
RpcEventFactory::fire() приймає будь-яку назву. Невідома назва генерується як rpc.custom_event (клас RpcEvent з масивом $eventData); бандл сам таких подій не генерує й не слухає.
Міграція зі старих версій
- З 8.0 класи подій живуть у
Ufo\JsonRpcBundle\EventDrivenModel\Events\*(раніше —Ufo\RpcObject\Events\*). - Подію
rpc.responseприбрано у 7.6 — використовуйтеrpc.pre_responseабоrpc.post_response. - З 10.3 бандл не зупиняє поширення
kernel.terminate/console.terminate, тож terminate-лістенери застосунку теж виконуються після RPC-запитів.