zendframework / zend-servicemanager

ServiceManager component from Zend Framework
BSD 3-Clause "New" or "Revised" License
188 stars 89 forks source link

Tuning lazy_services for production #274

Closed Orkin closed 5 years ago

Orkin commented 5 years ago

Hello,

I would like to tune the lazy services with the proxy manager for production. It seems there is a problem because it try to generate proxies again on each request even when they already exist.

https://github.com/Ocramius/ProxyManager/issues/437

Thanks

Ocramius commented 5 years ago

@Orkin would need a bit more than that: can this be reproduced in a test scenario, somehow?

Orkin commented 5 years ago

Ok so I use the Service Manager version 3.3.2 with Zend Expressive version 3.0.3

I have found 2 issues : The first one in development mode composer development-enable and this is my config/autoload/development.local.php :

<?php

declare(strict_types=1);

/**
 * Development-only configuration.
 *
 * Put settings you want enabled when under development mode in this file, and
 * check it into your repository.
 *
 * Developers on your team will then automatically enable them by calling on
 * `composer development-enable`.
 */

return [
...
    'dependencies' => [
        'lazy_services' => [
            // whether the generated proxy classes should be written to disk or generated on-the-fly
            'write_proxy_files' => false,
        ],
    ],
...
];

And my dependencies.global.php :

<?php

declare(strict_types=1);

return [
    // Provides application-wide services.
    // We recommend using fully-qualified class names whenever possible as
    // service names.
    'dependencies' => [
        'lazy_services' => [
            // directory where proxy classes will be written - default to system_get_tmp_dir()
            'proxies_target_dir' => \getcwd() . '/data/cache/OcramiusProxy', // in my docker container its /var/www/data/cache/OcramiusProxy

            // namespace of the generated proxies, default to "ProxyManagerGeneratedProxy"
            'proxies_namespace' => null,

            // whether the generated proxy classes should be written to disk or generated on-the-fly
            'write_proxy_files' => true,
        ],
    ],
];

The development.local.php write_proxy_files config overwrite the dependencies.global.php so in development mode the write_proxy_files === false

I don't have write and read permission on my folder /var/www/data/cache/OcramiusProxy and I have an error here https://github.com/Ocramius/ProxyManager/blob/master/src/ProxyManager/FileLocator/FileLocator.php#L30 I don't know why there is a need of the folder /var/www/data/cache/OcramiusProxy to be readable/writable when proxies are generated on the fly and not saved on the disk.

The second problem is in production mode composer development-disable, in this case write_proxy_files is set to true. I have a command that write proxies in my folder /var/www/data/cache/OcramiusProxy. After the run of the command I can found all my proxies. To be sure there is not read/write problem I tried with chmod 777 /var/www/data/cache/OcramiusProxy/*. And on each request file are write in this folder even they are present !

I hope it can help 😃

Ocramius commented 5 years ago

I don't know why there is a need of the folder /var/www/data/cache/OcramiusProxy to be readable/writable when proxies are generated on the fly and not saved on the disk.

This is just checking if the path you configured exists, nothing else.

And on each request file are write in this folder even they are present !

Seems like autoloading is failing for the proxies. Can you try dumping a proxy class name, then (fresh process) check a class_exists() of it? You may need to run the abstract factory once though.

Orkin commented 5 years ago

This is just checking if the path you configured exists, nothing else.

Ok I understand but it is really necessary to do this check when proxies are generated on the fly ? Because it do not need to exist. I'm agree to the fact to test if the configuration is ok but it can be blocking.

Seems like autoloading is failing for the proxies. Can you try dumping a proxy class name, then (fresh process) check a class_exists() of it? You may need to run the abstract factory once though.

It return false, it's really strange

Ocramius commented 5 years ago

when proxies are generated on the fly ?

Proxies are always generated on the fly, if they cannot be found. In production, you'd rely on the proxies to already exist.

Orkin commented 5 years ago

Hey, I found a solution, there was 2 bugs :

Thanks

Ocramius commented 5 years ago

Could you detail what your CLI script was doing? Would be useful for others hitting the same issue.

On Tue, 27 Nov 2018, 11:58 Florent Blaison <notifications@github.com wrote:

Closed #274 https://github.com/zendframework/zend-servicemanager/issues/274.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/zendframework/zend-servicemanager/issues/274#event-1989234392, or mute the thread https://github.com/notifications/unsubscribe-auth/AAJakNxThItVh9Ses_dsAi5_Stjg_B0qks5uzRrQgaJpZM4YQllT .

Orkin commented 5 years ago

Hello, sorry for the late reply :

my CLI script is doing nothing complicated, in fact it's just a command that load the Service Manager and autoloader to force creation of proxies class :

<?php

declare(strict_types=1);

namespace App\Presentation\Console\Command;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;

/**
 * @author Florent Blaison
 */
class GenerateOcramiusProxyCommand extends Command
{
    public function __construct()
    {
        parent::__construct();
    }

    protected function configure()
    {
        $this->setName('generate:ocramius-proxy')
             ->setDescription('Generate Ocramius Proxy files');
    }

    /**
     * @param InputInterface  $input
     * @param OutputInterface $output
     *
     * @return int|null|void
     * @throws \Exception
     */
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $ui = new SymfonyStyle($input, $output);

        $ui->text('Proxy classes generated');
    }
}
Ocramius commented 5 years ago

That command has no body though?

Orkin commented 5 years ago

@Ocramius Nop, its an empty command, I found this hack to make it work. This command is loaded by the DI and DI + autoloading create proxies