docs: rewrite JsonRpcBundle docs, add SDK docs, move them under docs/api
en/docs/api/json-rpc-bundle/functionality/events/post_execute.md
new file +103
−0
rpc.post_execute
Event name
rpc.post_execute
Constant
RpcEvent::POST_EXECUTE
Class
RpcPostExecuteEvent
Properties
mixed $result, RpcRequest $rpcRequest, Service $service, array $params
Built-in listeners
none
Dispatched once after successful method execution. $result is what the method returned, $params are the arguments after conversion.
The event is dispatched after rpc.pre_response: the response has already been built. Assigning a new $result does not change what the client receives. To change the response, use rpc.pre_response.
Not dispatched on error (rpc.error is dispatched instead), for a cached response and for the receipt of notifications/callback.
Usage examples
Method execution time
final class TimingListener
{
private array $started = [];
#[AsEventListener(RpcEvent::PRE_EXECUTE, priority: 2000)]
public function start(RpcPreExecuteEvent $event): void
{
$this->started[spl_object_id($event->rpcRequest)] = hrtime(true);
}
#[AsEventListener(RpcEvent::POST_EXECUTE)]
public function finish(RpcPostExecuteEvent $event): void
{
$key = spl_object_id($event->rpcRequest);
$ms = (hrtime(true) - ($this->started[$key] ?? hrtime(true))) / 1e6;
unset($this->started[$key]);
$this->metrics->histogram('rpc_duration_ms', $ms, ['method' => $event->service->name]);
}
}
Domain events
After a successful Order.pay, publish an event to the application bus:
#[AsEventListener(RpcEvent::POST_EXECUTE)]
final class OrderPaidListener
{
public function __construct(private MessageBusInterface $bus) {}
public function __invoke(RpcPostExecuteEvent $event): void
{
if ($event->service->name === 'Order.pay' && $event->result === true) {
$this->bus->dispatch(new OrderPaid($event->params['orderId']));
}
}
}
Move heavy work that should not delay the client to rpc.post_response — it is dispatched after the response has been sent.