Події життєвого циклу

← Події життєвого циклу

Ashterix

docs: rewrite JsonRpcBundle docs, add SDK docs, move them under docs/api

uk/docs/api/json-rpc-bundle/functionality/events/README.md новий файл +87 −0

Події життєвого циклу

Обробка кожного 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-запитів.