4

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?

RobMasters
  • 4,108
  • 2
  • 27
  • 34

3 Answers3

9

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.

theunraveler
  • 3,254
  • 20
  • 19
  • If you do this, be sure to also clear (or disable) php's realpath cache, as described in my answer below. Otherwise the APC classmap will simply be repopulated again with the wrong values. – Nathan Stretch May 02 '14 at 02:49
1

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

Community
  • 1
  • 1
jebbench
  • 283
  • 1
  • 4
  • 12
  • Thanks, but do you know how this would be called from the capifony deploy script? I was thinking I could create a Symfony2 command such as `my_namespace:apc:clear` containing the function call and execute this from capifony using `run "/path/to/app/console my_namespace:apc:clear"` in a post deploy hook, but I'm not sure if it matters that this will be using the CLI php instead of apache. Do you know if this makes any difference? – RobMasters Oct 12 '12 at 11:46
  • Yes, I think the CLI PHP has a separate cache. - http://stackoverflow.com/questions/911158/how-to-clear-apc-cache-entries – jebbench Oct 12 '12 at 12:19
  • Thanks for the heads up. That question definitely looks useful, I'm sure I'll be able to get it sorted now. I'll accept your answer but will also post an answer showing what I did to get it working... – RobMasters Oct 12 '12 at 12:51
  • Thanks, but I think theunraveler has the more helpful answer. – jebbench Oct 12 '12 at 13:02
  • You're not wrong. Sorry - I don't think it was there when I accepted yours. – RobMasters Oct 12 '12 at 14:01
1

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.

Community
  • 1
  • 1
Nathan Stretch
  • 1,028
  • 1
  • 11
  • 23