rpc.error

rpc.error

Назва події

rpc.error

Константа

RpcEvent::ERROR

Клас

RpcErrorEvent

Властивості

RpcRequest $rpcRequest, Throwable $exception, RpcError $rpcError

Помилка під час виконання запиту. $rpcError — об'єкт помилки, з якого буде сформовано відповідь; його можна замінити.

Коли генерується

  • Помилки валідації параметрів і #[RPC\Assertions].
  • Помилки конвертації параметрів (DTO).
  • Виняток або TypeError з методу.
  • Запит, позначений помилкою на попередніх етапах (setError()).
  • У консолі, inline-batch і через RpcExecutor — також для будь-якого іншого винятку обробки.
Нестиковка

В одиночному HTTP-запиті частина помилок (недійсний JSON, токен, невідомий метод, версія jsonrpc, batch) не проходить через rpc.error і не логується бандлом. Деталі — в Актуальних помилках.

Вбудовані лістенери

Пріоритет Лістенер Що робить
1000 RpcErrorListener Для ConstraintsImposedException додає перелік порушень у data
0 LoggerListener Пише помилку в лог (метод, параметри, дані)
-1000 RpcServerListener::onRpcError Формує відповідь з помилкою з $event->rpcError (rpc.pre_response) і зупиняє поширення

Що можна змінити

$event->rpcError — підтримуваний спосіб змінити помилку, яку отримає клієнт:

$event->rpcError = new RpcError($code, $message, $data);
  • Пріоритет між 1000 і 0 — ваша версія піде і в лог, і клієнту; між 0 і -1000 — лог побачить оригінал.
  • $rpcError створюється з $exception у конструкторі; присвоєння нового $exception його не перераховує.
  • Лістенери нижче -1000 не викликаються. Не зупиняйте поширення вище -1000 — відповідь з помилкою не буде сформовано.

Приклади використання

Приховати внутрішні подробиці

#[AsEventListener(RpcEvent::ERROR, priority: 500)]
final class HideInternalErrorsListener
{
    public function __construct(#[Autowire('%kernel.environment%')] private string $env) {}

    public function __invoke(RpcErrorEvent $event): void
    {
        if ($this->env === 'prod' && $event->exception instanceof RpcRuntimeException) {
            $event->rpcError = new RpcError(-32500, 'Internal server error', []);
        }
    }
}

Відправка в систему моніторингу

#[AsEventListener(RpcEvent::ERROR, priority: 100)]
final class SentryListener
{
    public function __invoke(RpcErrorEvent $event): void
    {
        \Sentry\withScope(function (\Sentry\State\Scope $scope) use ($event): void {
            $scope->setTag('rpc.method', $event->rpcRequest->getMethod());
            \Sentry\captureException($event->exception);
        });
    }
}

Інші ідеї

  • перетворення доменних винятків застосунку на власні коди помилок;
  • лічильник помилок за методом і кодом;
  • додавання request_id у data помилки для підтримки.