(Tentatively marking this as a bug report, although it's possible that I'm not fully grasping the Authcache + Cache Expiration + Authcache Enum workings, feel free to mark as support request if that is the case).

While trying to set up automatic cache expiration through Authcache Builtin Cache Expiration v2 (and dependencies) on a site that already had Authcache + Authcache Ajax set up and configured, I ran into the following issue:

Since we don't care about varying the cached pages per roles (elements that vary per user/role are retrieved as fragments), we implemented hook_authcache_key_properties() as follows:

/**
 * Implements hook_authcache_key_properties_alter().
 */
function module_authcache_key_properties_alter(&$properties) {
  // Do not vary the cache by roles.
  // Note that due to the way keys are generated, we still end up with a
  // separate cache entry for anonymous vs authenticated users.
  unset($properties['roles']);
}

This works fine, and limits the number of cache entries in the cache_page table.

However, now that we are trying to implement cache expiration, we ran into 2 issues:

A) Since we've removed the roles from key generation, Authcache Enumerate should not take these into account when generation all possible keys. However, the current API does not allow me to remove the 'roles' property from the list of properties returned in authcache_enum_authcache_enum_key_properties(). authcache_enum_key_properties_alter() only allows me to tinker with the generated keys, and not the properties-array used to calculate possible keys, so a) all keys generated by authcache_enum_user_keys() are incorrect and I need to remove them, b) I need to redo the calculation with the correct input properties.

B) We have about 15 separate base urls, and need a separate cache entry for any given page on each of these urls (since language of the page is derived from the base url. However, the default implementation of

hook_authcache_enum_key_properties()

is as follows:

/**
 * Implements hook_authcache_enum_key_properties().
 */
function authcache_enum_authcache_enum_key_properties() {
  global $base_root;

  $func = variable_get('authcache_enum_role_combine', '_authcache_enum_default_role_combine');

  return array(
    'base_root' => array(
      'name' => t('The root URL of the host, excluding the path'),
      'choices' => array($base_root),
    ),
    'roles' => array(
      'name' => t('User roles'),
      'choices' => call_user_func($func),
    ),
  );
}

It seems that there is no way to alter the 'choices' for base_root prior to key calculation, so not all possible cache keys are calculated, only those for the active domain.

Other than that, it feels that the current API functions go against the Drupal paradigm of having a hook_properties() and a hook_properties_alter(), where the properties_alter-hook allows you to change the values returned by the properties_hook. In the case of Authcache Enumerate, hook_authcache_enum_key_properties() returns the properties, while hook_authcache_enum_key_properties_alter() alters the calculated result, not the properties.

I've altered authcache_enum_user_keys() so that hook_authcache_enum_key_properties_alter() allows altering the input properties array, and a new hook hook_authcache_enum_user_keys_alter() allows altering of the calculated values.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Status: Needs review » Needs work

The last submitted patch, authcache-enum-properties-altering.patch, failed testing.

Status: Needs work » Needs review

Status: Needs review » Needs work

The last submitted patch, authcache-enum-properties-altering.patch, failed testing.

znerol’s picture

Version: 7.x-2.0-beta7 » 7.x-2.x-dev
Status: Needs work » Needs review

Seems like the test-bot does not download all dependencies. Perhaps that works better on the dev branch.

Instead of renaming an existing hook, I'd prefer to introduce a new one. In fact I believe that the alter-hook is correct, since the data structure is very similar to the one from hook_authcache_key_properties. In contrast the hook invoked on top of the function is more like an info-hook. Therefore I'd rather rename that. It would even be possible to keep the old around for some time for compatibility reasons. E.g.:

if (!isset($info)) {
  $properties_info = module_invoke_all('authcache_enum_key_property_info');
  drupal_alter('authcache_enum_key_property_info', $properties_info);

  // Backwards compatibility.
  $properties_info += module_invoke_all('authcache_enum_key_properties');

  [...]

  drupal_alter('authcache_enum_key_properties', $info);
}

mr.baileys’s picture

Makes sense, updated patch attached:

  • Renames hook_authcache_enum_key_properties() to hook_authcache_enum_key_property_info().
  • Adds hook_authcache_enum_key_property_info_alter()
  • Property info collection: invoke hook_authcache_enum_key_property_info(), followed by hook_authcache_enum_key_properties() for backwards compatibility, followed by hook_authcache_enum_key_property_info_alter().
  • Leaves hook_authcache_enum_properties_alter() as it is.

Note that I'm seeing numerous test failures locally, but I'm getting the same failures without this patch applied, so it might be related to my environment.

znerol’s picture

Thanks, looks good. About the second problem (base_root['choices'] being populated by only the active site), do you think there is a generic solution for that problem? Maybe try to retrieve a list of base URLs from the language module?

znerol’s picture

I do not have much experience with multilingual sites. Maybe something like this might work:


global $base_root;
$base_roots = array($base_root);
if (drupal_multilingual()) {
  foreach (language_list('enabled') as $language) {
    $options = array(
      'absolute' => TRUE,
      'language' => $language->language,
    );
    $base_roots[] = url('<front>', $options);
  }
}

array_unique($base_roots) // -> use that in the base root choices array.
znerol’s picture

Seems like the following code fragment works for prefix as well as domain based multilingual sites (tried it in a PHP block):

global $base_root;
$base_roots = array($base_root);
if (drupal_multilingual()) {
  $languages = language_list('enabled');
  foreach ($languages[1] as $language) {
    $options = array(
      'absolute' => TRUE,
      'language' => $language,
    );
    $base_roots[] = url('<front>', $options);
  }
}

var_dump($base_roots);
znerol’s picture

I wonder whether we need to add an option for https-links as well?

znerol’s picture

#9 only makes sense for domain based language negotiation. When using a path prefix, then the $base_root will stay the same. Also I'm wondering whether it is really desirable to always expire all the languages. If the expiry hook was fired after a node translation was edited, then it is likely that only pages of that language should be expired - at least by default.

With #6 it is possible to customize the behavior, so I'm tempted to just commit that and ignore the base root part. Any opinions?

znerol’s picture

Uploading #6 again to trigger a new test run after #2546624: Add test coverage for Authcache Enum API.

mr.baileys’s picture

#9 only makes sense for domain based language negotiation. When using a path prefix, then the $base_root will stay the same. Also I'm wondering whether it is really desirable to always expire all the languages. If the expiry hook was fired after a node translation was edited, then it is likely that only pages of that language should be expired - at least by default.

In our case we are actually not translating nodes, and each node is usually only viewed in one language. However, since it is technically possible to visit a Dutch node on an English domain, we decided to include the base URL in enum key generation (hence this patch :) ). I assume that you'd also want expiry across languages when certain properties are shared (for example the price on a product).

As per #11, given that every site is unique, I think it's fine to leave customising the behaviour in the hands of implementors. With the patch it should be trivial to add or remove factors for key generation and tailor expiration for any site.

znerol’s picture

Add tests.

joelpittet’s picture

Status: Needs review » Needs work
+++ b/modules/authcache_enum/authcache_enum.api.php
@@ -25,14 +25,28 @@ function hook_authcache_enum_anonymous_keys_alter(&$keys) {
+ * in the future. Use hook_authcache_key_property_info() instead.

Was upgrading something to test this out and I think this may be wrong?

Should this be hook_authcache_enum_key_property_info()?

joelpittet’s picture

Also once I fixed that, I got this error after saving.

Warning: Illegal string offset 'choices' in authcache_enum_user_keys() (line 94 of /authcache/modules/authcache_enum/authcache_enum.module).

Edit: this may because I had both hooks implemented...

mr.baileys’s picture

Status: Needs work » Needs review
FileSize
655 bytes
9.39 KB

#15 => good catch, updated.

joelpittet’s picture

Status: Needs review » Reviewed & tested by the community

This is looking pretty good and doesn't hurt having more tests:)

It got some language stuff working with this:


/**
 * Implements hook_authcache_key_properties().
 */
function M_authcache_key_properties() {
  global $language;
  return array('lang' => $language->language);
}

/**
 * Implements hook_authcache_enum_key_property_info().
 */
function M_authcache_enum_key_property_info() {
  $languages = language_list('enabled');
  return array(
    'lang' => array(
      'name' => t('Language support'),
      'choices' => array_keys($languages[1]),
    ),
  );
}

  • znerol committed 98f764d on 7.x-2.x authored by mr.baileys
    Issue #2543352 by mr.baileys, znerol: Unable to alter authcache_enum...
znerol’s picture

Status: Reviewed & tested by the community » Fixed

Thank you, and sorry for the delay.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.