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],
) {}
Method response caching
By default, response caching for your RPC methods is disabled, and every time you call the API the method is executed.
However, for certain methods whose result rarely changes, it sometimes makes sense to enable response caching to speed up request processing, preserve rate limits, reduce load on parts of the system, etc.
Responses are stored in a separate cache pool of the bundle (rpc.cache.pool, filesystem-based in %kernel.cache_dir%). It can be replaced with any application pool, for example a shared Redis one, via cache.pool in the configuration.
Enabling caching is as simple as possible: all you need to do is add the #[RPC\Cache] attribute to the method.
namespace App\Api\Procedures;
use Ufo\RpcObject\RPC;
class SomeApiMethod implements IRpcService
{
#[RPC\Cache]
public function methodThatWorksForALongTime(): void {}
}
This configuration caches the response for one minute; every subsequent request to this method with the same parameters gets the response instantly from the cache.
The cache key consists of the method implementation (Class::method), the API version and the sorted request parameters, so the order of keys in nested objects does not affect the key. Methods without #[RPC\Cache] do not access the cache at all.
As usual, you can clear the cache by running the Symfony command
bin/console cache:clear
If needed, you can increase the cache lifetime by passing the number of seconds in the lifetimeSecond parameter. For convenience, there are constants that cover most needs, but you can also pass the value as a plain number.
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
You can also change the environments in which caching can be enabled. By default, caching works only in the prod environment. But you can change this by passing an array of environment names in which you want to cache results. In the example below, the result is cached for one day in the prod and dev environments.
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 {}
}
Bypassing the cache for a single request
The special parameter $rpc.ignoreCache forces the response to be computed again and overwritten in the cache:
{"jsonrpc": "2.0", "id": 1, "method": "SomeApiMethod.methodThatWorksForALongTime", "params": {"$rpc": {"ignoreCache": true}}}
#[RPC\CacheRelation]
A method that changes data can clear the cached responses of related methods and, if needed, warm them up again right away.
public function __construct(
public ?string $serviceFQCN = null, // class of the related methods; defaults to the current one
public array $methods = [], // names of the related methods
public bool $warmUp = false, // run them again right away to fill the cache
)
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 { /* ... */ }
}
After a successful User.rename {"id": 5, ...}, the cached User.get {"id": 5} is deleted and rebuilt. The key of the related request is made of those parameters of the current request whose names match the parameters of the related method. The attribute can be specified multiple times.
Invalidation runs on the rpc.post_response event, i.e. after the response has been sent to the client. It does not run for an error response.
On multiple servers, configure a shared cache.pool — otherwise invalidation only takes effect on the server that handled the request.
Managing the cache from code
Ufo\JsonRpcBundle\Server\RpcCache\RpcCacheService provides the same capabilities programmatically:
| Method | What it does |
|---|---|
deleteRelationCache(string $class, array $methods, array $params) |
Deletes cached responses of the specified methods |
warmCache(string $class, array $methods, array $params, bool $deleteCache = true) |
Deletes and immediately rebuilds the cache |
deleteRequestCache(RpcRequest $request) |
Deletes the response of a single request |
public function __construct(private RpcCacheService $rpcCache) {}
// after updating an entity outside RPC
$this->rpcCache->deleteRelationCache(UserProcedure::class, ['get'], ['id' => $id]);