Блокування одночасних викликів

Summary

Classname Lock
Namespace Ufo\RpcObject\RPC
Target method
public function __construct(
    public ?string $paramName = null,
    public ?int $ttl = null,
)

Блокування одночасних викликів

Деякі методи не можна виконувати паралельно: оплата одного замовлення, генерація звіту, синхронізація з зовнішньою системою. Атрибут #[RPC\Lock] не дає запустити метод, поки попередній виклик ще виконується.

use Ufo\RpcObject\RPC;

#[RPC\Lock(paramName: 'orderId', ttl: RPC\Lock::T_10_SECOND)]
public function pay(string $orderId): bool
{
    // ...
}
  • paramName — блокування окремо для кожного значення параметра: два виклики pay з різними orderId виконуються одночасно, з однаковим — ні. Без paramName метод блокується цілком, незалежно від аргументів.
  • ttl — час життя блокування в секундах, щоб воно не лишилося назавжди, якщо процес впав. Константи: T_SECOND, T_2_SECOND, T_5_SECOND, T_10_SECOND, T_20_SECOND, T_30_SECOND.

Блокування захоплюється перед виконанням методу (подія rpc.pre_execute) і звільняється після нього, зокрема при помилці. Захоплення блокувальне (acquire(true)): паралельний виклик з тим самим ключем чекає, доки блокування звільниться. Якщо сховище блокувань повідомляє про конфлікт, виклик завершується помилкою:

{
    "jsonrpc": "2.0",
    "id": 1,
    "error": {
        "code": -32400,
        "message": "Method 'Order.pay' is locked."
    }
}
Відома нестиковка

У поточній версії конфлікт не перетворюється на помилку: паралельний виклик чекає звільнення блокування. Деталі й обхідний шлях — у розділі Актуальні помилки.

Блокування реалізоване на Symfony Lock; для нього потрібне розширення ext-sysvsem.