schmittjoh / JMSSerializerBundle

Easily serialize, and deserialize data of any complexity (supports XML, JSON, YAML)
http://jmsyst.com/bundles/JMSSerializerBundle
MIT License
1.8k stars 312 forks source link

Add support for kernel.cache_warmer #611

Closed Xymanek closed 6 years ago

Xymanek commented 6 years ago

Version: latest (2.2.0)

Right now we have bin/console cache:warmup in our CD pipeline. Unfortunately, jms_serializer folder remains empty (unlike doctrine and twig). This causes performance hit on the first request that uses the serializer.

This is similar to #415 however this is about cache warmup instead of clearing

pdugas commented 6 years ago

This also means it cannot be used on platforms like Google App Engine's Standard PHP environment where writes to the local filesystem are not allowed. Would really like a warmup option for my Entity classes so I can use JMS Serializer.

goetas commented 6 years ago

And what should be a strategy to do it?

Doctrine works on entites, twig on templates, but the serializer is able to serializer virtually "any" class in the project.

What about "warming up" all the classes in specific folders? Can be a solution? Better ideas?

On 15 Nov 2017 17:18, "Paul Dugas" notifications@github.com wrote:

This also means it cannot be used on platforms like Google App Engine's Standard PHP environment where writes to the local filesystem are not allowed. Would really like a warmup option for my Entity classes so I can use JMS Serializer.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/schmittjoh/JMSSerializerBundle/issues/611#issuecomment-344644509, or mute the thread https://github.com/notifications/unsubscribe-auth/AAvaJ8V45tLPrTkJyxvUZUInr2VQghFdks5s2w7UgaJpZM4QW1JD .

pdugas commented 6 years ago

I did two things to make it work.

First, I commented out the is_dir() and is_writeable() checks in JMS' Metadata\Cache\FileCache constructor. Up on AppEngine, the is_writeable() return false. The check isn't necessary because of the next step.

Second, I created my own CacheWarmer to generate the cache files for my entities.

namespace AppBundle\CacheWarmer;

use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface;
use JMS\Serializer\SerializerInterface;

class EntitySerializerCacheWarmer implements CacheWarmerInterface
{
    private $em;
    private $serializer;

    public function __construct(EntityManagerInterface $em, SerializerInterface $serializer)
    {
        $this->em = $em;
        $this->serializer = $serializer;
    }

    public function warmUp($cacheDir)
    {
        foreach ($this->em->getConfiguration()->getMetadataDriverImpl()->getAllClassNames() as $class) {
            if (strpos($class, 'AppBundle\Entity') === 0) {
                $this->serializer->serialize(new $class(), 'json'); // result ignored
            }
        }
    }

    public function isOptional()
    {
        return true;
    }
}

Now I can cache:warmup and deploy. Working so far though only minimally tested.

pdugas commented 6 years ago

More generically, I think a way to list the classes that should be "warmed" makes sense. Maybe a way to specify classes in a namespace or just EM entities.

The strpos() check in my code was needed to prevent it from trying to serialize Gedmo\Loggable\Entity\MappedSuperclass\AbstractLogEntry which could not be instantiated because it's abstract. I'm planning on creating my own derivation of that baseclass so my API can expose logs.

pdugas commented 6 years ago

Oh, and making the list of classes to warm empty by default would make the addition of a custom CacheWarmer to the bundle backwards compatible.

goetas commented 6 years ago

https://github.com/schmittjoh/JMSSerializerBundle/pull/615 is the WIP PR to solve the issue