laminas / laminas-modulemanager

Modular application system for laminas-mvc applications
https://docs.laminas.dev/laminas-modulemanager/
BSD 3-Clause "New" or "Revised" License
30 stars 18 forks source link

Error when when the cache file is written multiple times in a short time period #18

Open SteffenAnders opened 3 years ago

SteffenAnders commented 3 years ago

Hi guys,

i have just updated laminas/laminas-modulemanager from 2.8.4 to 2.10.1.

Our application.config.php looks like this:

<?php

return [
    // Retrieve list of modules used in this application.
    'modules' => [
        ...
    ],

    // These are various options for the listeners attached to the ModuleManager
    'module_listener_options' => [
        // This should be an array of paths in which modules reside.
        // If a string key is provided, the listener will consider that a module
        // namespace, the value of that key the specific path to that module's
        // Module class.
        'module_paths' => [
            __DIR__ . '/../module',
            __DIR__ . '/../vendor',
        ],

        // Whether or not to enable a configuration cache.
        // If enabled, the merged configuration will be cached and used in
        // subsequent requests.
        'config_cache_enabled' => (bool) '1',

        // The key used to create the configuration cache file name.
        'config_cache_key' => 'application.config.cache',

        // Whether or not to enable a module class map cache.
        // If enabled, creates a module class map cache which will be used
        // by in future requests, to reduce the autoloading process.
        'module_map_cache_enabled' => (bool) '1',

        // The key used to create the class map cache file name.
        'module_map_cache_key' => 'application.module.cache',

        // The path in which to cache merged configuration.
        'cache_dir' => __DIR__ . '/../cache',
    ],
];

After deploying and publishing a new version of our application, several hundred requests immediately call up the website. And every one of these requests wants to generate the cache files of the application, because they do not exist initially.

With the old version of laminas/laminas-modulemanager (2.8.4) there were usually some warnings which was caused by a write conflict of multiple rename() calls for the same filepath. But that was OK for me, because after a few seconds the warnings disappeared and the website was still usable from the beginning.

The warnings looked like this:

FastCGI sent in stderr: "PHP message: PHP Warning:  rename(/tmp/c79d2428f255f122db8f0dd7c108798bMCtoSc,/home/x/releases/xxx/xxx/config/../cache/module-config-cache.application.config.cache.php): Permission denied in /home/xxx/releases/xxx/xxx/vendor/laminas/laminas-modulemanager/src/Listener/AbstractListener.php on line 73

But since the new version of laminas/laminas-modulemanager (2.10.1) real exceptions instead of warnings are thrown in this case. This results in the website not being callable for up to 30 seconds, because apparently several requests or processes are blocking each other,

The exceptions look like this:

FastCGI sent in stderr: "PHP message: PHP Fatal error:  Uncaught Webimpress\SafeWriter\Exception\RuntimeException: Could not create temporary file in directory "xxx" in /home/xxx/releases/xxx/xxx/vendor/webimpress/safe-writer/src/Exception/RuntimeException.php:28

#0 /home/xxx/releases/xxx/xxx/vendor/webimpress/safe-writer/src/FileWriter.php(37): Webimpress\SafeWriter\Exception\RuntimeException::unableToCreateTemporaryFile('xxx')
#1 /home/xxx/releases/xxx/xxx/vendor/laminas/laminas-modulemanager/src/Listener/AbstractListener.php(77): Webimpress\SafeWriter\FileWriter::writeFile('xxx')
#2 /home/xxx/releases/xxx/xxx/vendor/laminas/laminas-modulemanager/src/Listener/ConfigListener.php(183): Laminas\ModuleManager\Listener\AbstractListener->writeArrayToFile('xxx', Array)

I think it has something to do with the changes of the following pull request: https://github.com/laminas/laminas-modulemanager/pull/9

It is nice that the new "SafeWriter" now ensures that no broken cache files will be generated. However, the problem with multiple requests trying to write the same file at the same time is still present and even worse than before due to the throwing excpetions instead of ignorable warnings.

What can we do to avoid the problem? Is there a try..catch possibility, so that in case of a "SafeWriter" exception the cache generation will simply be skipped, because the file was already generated by an other process?

Or is there a way to generate the cache files via CLI before the actual release of the website (See: https://github.com/laminas/laminas-modulemanager/issues/5)?

In the meantime we are using the old version 2.8.4. :)

SteffenAnders commented 3 years ago

ping @weierophinney 😄

SteffenAnders commented 3 years ago

Any updates here? @weierophinney

SteffenAnders commented 3 years ago

@michalbundyra @froschdesign

froschdesign commented 3 years ago

@SteffenAnders

After deploying and publishing a new version of our application… … Or is there a way to generate the cache files via CLI before the actual release of the website (See: #5)?

Have you tried to create a CLI command and perform an HTTP request?