Кешування відповіді методу

Summary

Classname

Cache

Namespace

Ufo\RpcObject\RPC

Target

method

Constructor

/**
 * Cache constructor.
 *
 * @param int $lifetimeSecond
 * @param array $environments
 */
public function __construct(
    public int $lifetimeSecond = self::T_MINUTE,
    public array $environments = [self::ENV_PROD],
) {}

Кешування відповіді методу

За замовченням кешування відповідей ваших RPC методів вимкнено і кожен раз, коли ви викликаєте API, метод буде викликано.

Проте, інколи, для певних методів, результат яких змінюється не часто, є сенс ввімкнути кешування відповіді задля підвищення швидкості обробки запитів, для збереження лімітів, зниження навантаження на частини системи, тощо.

Відповіді зберігаються в окремому пулі кешу бандла (rpc.cache.pool, файловий у %kernel.cache_dir%). Його можна замінити будь-яким пулом застосунку, наприклад спільним Redis, через cache.pool у налаштуваннях.

Ввімкнути кешування максимально просто, єдине що вам потрібно зробити це до певного методу додати атрибут #[RPC\Cache].

namespace App\Api\Procedures;  
  
use Ufo\RpcObject\RPC;  
  
class SomeApiMethod implements IRpcService  
{  
    #[RPC\Cache]  
    public function methodThatWorksForALongTime(): void {}  
}

Це налаштування дозволить кешувати відповідь впродовж однієї хвилини, кожен наступний запит на цей метод з тими самими параметрами буде отримувати відповідь миттєво з кеша.

Ключ кешу складається з реалізації методу (Class::method), версії API та відсортованих параметрів запиту, тож порядок ключів у вкладених об'єктах на ключ не впливає. Методи без #[RPC\Cache] до кешу взагалі не звертаються.

Скинути кеш можна як і завжди, виконавши Symfony команду

bin/console cache:clear

В разі потреби ви можете збільшити час життя кеша, передавши кількість секунд в параметр lifetimeSecond. Для зручності створені константи, які покривають більшість потреб, але ви також можете передати значення простим числом.

use Ufo\RpcObject\RPC\Cache;  
  
Cache::T_MINUTE; // 60  
Cache::T_5_MINUTES; // 300  
Cache::T_10_MINUTES; // 600  
Cache::T_30_MINUTES; // 1800  
Cache::T_HOUR; // 3600  
Cache::T_2_HOURS; // 7200  
Cache::T_5_HOURS; // 18000  
Cache::T_10_HOURS; // 36000  
Cache::T_DAY; // 86400  
Cache::T_2_DAYS; // 172800  
Cache::T_3_DAYS; // 259200  
Cache::T_5_DAYS; // 432000  
Cache::T_10_DAYS; // 864000  
Cache::T_WEEK; // 604800  
Cache::T_2_WEEKS; // 1209600  
Cache::T_3_WEEKS; // 1814400  
Cache::T_MONTH; // 2592000  
Cache::T_2_MONTHS; // 5184000  
Cache::T_3_MONTHS; // 7776000  
Cache::T_HALF_YEAR; // 15724800  
Cache::T_YEAR; // 31536000

Також ви можете змінити налаштування оточення на якому кеш може бути ввімкнений. За замовченням кешування працює лише в оточенні prod. Але ви можете це змінити передавши масивом назви оточень, в яких хочете кешувати результати. У прикладі нижче результат буде кешуватися протягом однієї доби для prod і dev оточень.

namespace App\Api\Procedures;  
  
use Ufo\RpcObject\RPC;  
  
class SomeApiMethod implements IRpcService  
{  
    #[RPC\Cache(lifetimeSecond: RPC\Cache::T_DAY, environments: ['dev', 'prod'])]  
    public function methodThatWorksForALongTime(): void {}  
}

Обійти кеш для одного запиту

Спеціальний параметр $rpc.ignoreCache змушує обчислити відповідь заново й перезаписати її в кеші:

{"jsonrpc": "2.0", "id": 1, "method": "SomeApiMethod.methodThatWorksForALongTime", "params": {"$rpc": {"ignoreCache": true}}}

#[RPC\CacheRelation]

Метод, що змінює дані, може скидати закешовані відповіді пов'язаних методів і, за потреби, одразу прогрівати їх знову.

public function __construct(
    public ?string $serviceFQCN = null,  // клас пов'язаних методів; за замовчуванням — поточний
    public array $methods = [],          // назви пов'язаних методів
    public bool $warmUp = false,         // одразу виконати їх знову, щоб наповнити кеш
)
use Ufo\RpcObject\RPC;

#[RPC\Info('User')]
final class UserProcedure implements IRpcService
{
    #[RPC\Cache(lifetimeSecond: RPC\Cache::T_HOUR)]
    public function get(int $id): UserDto { /* ... */ }

    #[RPC\CacheRelation(methods: ['get'], warmUp: true)]
    public function rename(int $id, string $name): bool { /* ... */ }
}

Після успішного User.rename {"id": 5, ...} закешований User.get {"id": 5} видаляється і будується заново. Ключ пов'язаного запиту складається з тих параметрів поточного запиту, чиї назви збігаються з параметрами пов'язаного методу. Атрибут можна вказувати кілька разів.

Інвалідація виконується на події rpc.post_response, тобто після відправлення відповіді клієнту. Для відповіді з помилкою вона не запускається.

На кількох серверах налаштуйте спільний cache.pool — інакше інвалідація спрацює лише на сервері, що обробив запит.

Керування кешем з коду

Ufo\JsonRpcBundle\Server\RpcCache\RpcCacheService дає ті самі можливості програмно:

Метод Що робить
deleteRelationCache(string $class, array $methods, array $params) Видаляє кешовані відповіді вказаних методів
warmCache(string $class, array $methods, array $params, bool $deleteCache = true) Видаляє й одразу заново будує кеш
deleteRequestCache(RpcRequest $request) Видаляє відповідь одного запиту
public function __construct(private RpcCacheService $rpcCache) {}

// після оновлення сутності поза RPC
$this->rpcCache->deleteRelationCache(UserProcedure::class, ['get'], ['id' => $id]);