Deploying Symfony2 app with Capifony - APC loader

2019-05-06 16:18发布

问题:

I've recently upgraded my Symfony2 application to 2.1 and migrated it to a new server, so I figured I'd configure Capifony to make deploying simpler. Everything has gone great except for the fact that it now doesn't make use of the APCLoader, so I've had to comment this out temporarily until it's sorted.

Here's the relevant code from app.php:

$loader = require_once __DIR__.'/../app/bootstrap.php.cache';

// Use APC for autoloading to improve performance.
// Change 'sf2' to a unique prefix in order to prevent cache key conflicts
// with other applications also using APC.

$loader = new ApcClassLoader('my_prefix', $loader);
$loader->register(true);

The problem is that 'my_prefix' isn't unique per release so it'll end up trying to look for cached files that belong to previous releases, which may or may not still be there. This is obviously a very big problem!

What would be the best solution for this? Should I somehow write a task that capifony will run before deploying that changes the prefix to something unique, such as the #{latest_release} variable? Or should I somehow reset the entire contents of the APC cache after each deploy?

I'm not too sure of the best way to do either of these things, so if you'd recommend one of them could you please point me in the right direction to be able to implement it? Or is there an alternative solution that I haven't thought of?

回答1:

You could use the ApcBundle, which provides a command that will create new file in the web/ directory, execute it through HTTP, then remove it. Then, you could use your run "/path/to/app/console apc:clear" command in your deployment script.



回答2:

You could try clearing the APC cache.

The easiest way to do this is to restart Apache.

You could also write a PHP script to do so:

<?php
apc_clear_cache();

See:

Does a graceful Apache restart clear APC?

http://php.net/manual/en/function.apc-clear-cache.php



回答3:

Another, potentially simpler solution to this would be to simply build a classmap file as part of your release process, instead of using APC for the class map. I haven't been able to track down the cause (yet, anyway), but I've found that even when I clear the apc user cache after deploying a new release, the old release can still pollute the cache. (I'm not sure how, since I use a method like that suggested by theunraveler to clear, and I do so after updating the symlink to the new release, so the old files should no longer be accessed, but it still does happen. Edit: Figured out why this happens. See https://stackoverflow.com/a/22680064/160565)

Anyway, I ended up just switching to using composer to dump an autoloader file as desribed in the "Use Composer's Class Map Functionality" section here: http://symfony.com/doc/current/book/performance.html

Basically you need to remove the ApcClassLoader stuff from app.php, then add this line to your deployment:

php composer.phar dump-autoload --optimize

I'm not sure what the efficiency is of using a classmap file vs using APC to cache the class locations directly, but it doesn't seem to have a noticeable effect on performance. Either one is obviously a significant boost over manually scanning the filesystem for each lookup.

Edit: Also, if you do take the approach of clearing the APC cache after deploying a new release, make sure you also clear php's realpath cache (or disable it), as described here. Otherwise php will continue accessing files from your old release after the cache has been cleared, which will cause it to be repopulated with the wrong paths.

In fact, it's a good idea to clear php's realpath cache on release anyway (or disable it), because otherwise any non-php files in your project will be out of sync with the php files until the cache expires.