Deploying Symfony2 app with Capifony - APC loader still uses previous release
Asked Answered
U

3

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?

Unexceptional answered 12/10, 2012 at 11:26 Comment(0)
L
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.

Laburnum answered 12/10, 2012 at 12:56 Comment(1)
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.Jabber
N
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

Nazarite answered 12/10, 2012 at 11:39 Comment(5)
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?Unexceptional
Yes, I think the CLI PHP has a separate cache. - #911658Nazarite
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...Unexceptional
Thanks, but I think theunraveler has the more helpful answer.Nazarite
You're not wrong. Sorry - I don't think it was there when I accepted yours.Unexceptional
J
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://mcmap.net/q/1021155/-the-controller-for-uri-is-not-callable-using-annotations)

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.

Jabber answered 27/3, 2014 at 6:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.