user3886650
user3886650

Reputation: 159

Use redis to cache duplicate requests in symfony2

This is my current setup:

snc_redis:
    clients:
        default:
            type: predis
            alias: cache
            dsn: "redis://127.0.0.1"
    doctrine:
            metadata_cache:
                client: cache
                entity_manager: default
                document_manager: default
            result_cache:
                client: cache
                entity_manager: [bo, aff, fs]
            query_cache:
                client: cache
                entity_manager: default

I have an API which gets multiple duplicate requests (usually in quick succession), can I use this setup to send back a cached response on duplicate request? Also is it possible to set cache expiry?

Upvotes: 2

Views: 1328

Answers (2)

user3886650
user3886650

Reputation: 159

In the end I created a cache manager and registered it as a service called @app_cache.

use Predis;

class CacheManager
{
    protected $cache;

    function __construct()
    {
        $this->client = new Predis\Client();
    }

    /**
     * @return Predis\Client
     */
    public function getInstance()
    {
        return $this->client;
    }
}

In the controller I can then md5 the request_uri

$id = md5($request->getRequestUri()); 

Check it exists, if it does return the $result

if($result = $app_cache->get($id)) {
   return $result;
}

If it doesn't do..whatever...and save the response for next time

$app_cache->set($id,$response);

To set the expiry use the 3rd and 4th parameter ex = seconds and px = milliseconds.

$app_cache->set($id,$response,'ex',3600);

Upvotes: 0

user4545769
user4545769

Reputation:

From the config sample you provided I'm guessing you want to cache the Doctrine results rather than the full HTTP responses (although the latter is possible, see below).

If so, the easiest way to do this is that whenever you create a Doctrine query, set it to use the result cache which you've set up above to use redis.

$qb = $em->createQueryBuilder();
// do query things
$query = $qb->getQuery();
$query->useResultCache(true, 3600, 'my_cache_id');

This will cache the results for that query for an hour with your cache ID. Clearning the cache is a bit of a faff:

$cache = $em->getConfiguration()->getResultCacheImpl();
$cache->delete('my_cache_id');

If you want to cache full responses - i.e. you do some processing in-app which takes a long time - then there are numerous ways of doing that. Serializing and popping it into redis is possible:

$myResults = $service->getLongRunningResults();
$serialized = serialize($myResults);
$redisClient = $container->get('snc_redis.default');
$redisClient->setex('my_id', $serialized, 3600);

Alternatively look into dedicated HTTP caching solutions like varnish or see the Symfony documentation on HTTP caching.

Edit: The SncRedisBundle provides its own version of Doctrine's CacheProvider. So whereas in your answer you create your own class, you could also do:

my_cache_service:
    class: Snc\RedixBundle\Doctrine\Cache\RedisCache
    calls:
        - [ setRedis, [ @snc_redis.default ] ]

This will do almost exactly what your class is doing. So instead of $app_cache->get('id') you do $app_cache->fetch('id'). This way you can switch out the backend for your cache without changing your app class, just the service description.

Upvotes: 3

Related Questions