Skip to content

Instantly share code, notes, and snippets.

@neetumorwani
Created March 23, 2016 12:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save neetumorwani/d30716683d6ee1c6f6a3 to your computer and use it in GitHub Desktop.
Save neetumorwani/d30716683d6ee1c6f6a3 to your computer and use it in GitHub Desktop.
<?php
/**
* @file
* Contains Drupal\akamai\Plugin\Purge\Purger\AkamaiPurger.
*/
namespace Drupal\akamai\Plugin\Purge\Purger;
use Drupal\purge\Plugin\Purge\Purger\PurgerBase;
use Drupal\purge\Plugin\Purge\Purger\PurgerInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use \Drupal\purge\Plugin\Purge\Invalidation\InvalidationInterface;
/**
* Akamai Purger.
*
* @PurgePurger(
* id = "akamai",
* label = @Translation("Akamai Purger"),
* description = @Translation("Provides a Purge service for Akamai CCU."),
* types = {"url", "everything"},
* configform = "Drupal\akamai\Form\ConfigForm",
* )
*/
class AkamaiPurger extends PurgerBase implements PurgerInterface {
/**
* Web services client for Akamai API.
*
* @var \Drupal\akamai\AkamaiClient
*/
protected $client;
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('config.factory')
);
}
/**
* Constructs a \Drupal\Component\Plugin\AkamaiPurger.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
* @param string $plugin_id
* The plugin_id for the plugin instance.
* @param mixed $plugin_definition
* The plugin implementation definition.
* @param \Drupal\Core\Config\ConfigFactoryInterface $config
* The factory for configuration objects.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, ConfigFactoryInterface $config) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->client = \Drupal::service('akamai.edgegridclient');
}
/**
* {@inheritdoc}
*/
public function getTimeHint() {
// @todo Create a configurable max timeout.
return 4.00;
}
/**
* {@inheritdoc}
*/
public function invalidate(array $invalidations) {
foreach ($invalidations as $invalidation) {
$invalidation->setState(InvalidationInterface::PROCESSING);
$invalidation_type = $invalidation->getPluginId();
switch ($invalidation_type) {
case 'url':
$urls_to_clear[] = $invalidation;
break;
// @todo implement other invalidation types
}
}
$this->client->purgeUrls($urls_to_clear);
}
}
@nielsvm
Copy link

nielsvm commented Mar 23, 2016

This Gist thing still doesn't allow me to comment between the lines, so I've copied the whole thing and do it manually:

<?php
/**
 * @file
 * Contains Drupal\akamai\Plugin\Purge\Purger\AkamaiPurger.
 */
namespace Drupal\akamai\Plugin\Purge\Purger;
use Drupal\purge\Plugin\Purge\Purger\PurgerBase;
use Drupal\purge\Plugin\Purge\Purger\PurgerInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use \Drupal\purge\Plugin\Purge\Invalidation\InvalidationInterface;

I'm missing a newline between this use statement and /** (code style).

/**
 * Akamai Purger.
 *
 * @PurgePurger(
 *   id = "akamai",
 *   label = @Translation("Akamai Purger"),
 *   description = @Translation("Provides a Purge service for Akamai CCU."),
 *   types = {"url", "everything"},
 *   configform = "Drupal\akamai\Form\ConfigForm",
 * )
 */
class AkamaiPurger extends PurgerBase implements PurgerInterface {

Missing newline.

  /**
   * Web services client for Akamai API.
   *
   * @var \Drupal\akamai\AkamaiClient
   */
  protected $client;

Missing newline.

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    return new static(
      $configuration,
      $plugin_id,
      $plugin_definition,
      $container->get('config.factory')
    );
  }

Missing newline.

  /**
   * Constructs a \Drupal\Component\Plugin\AkamaiPurger.
   *
   * @param array $configuration
   *   A configuration array containing information about the plugin instance.
   * @param string $plugin_id
   *   The plugin_id for the plugin instance.
   * @param mixed $plugin_definition
   *   The plugin implementation definition.
   * @param \Drupal\Core\Config\ConfigFactoryInterface $config
   *   The factory for configuration objects.
   */
  public function __construct(array $configuration, $plugin_id, $plugin_definition, ConfigFactoryInterface $config) {
    parent::__construct($configuration, $plugin_id, $plugin_definition);
    $this->client = \Drupal::service('akamai.edgegridclient');

Oops, you're using \Drupal which isn't intended to be used by new Drupal code, its to aid old code porting over. Since Purgers adhere to ContainerFactoryPluginInterface, you can... should override ::create() which has direct container access and retrieve akamai.edgegridclient from there, to then inject it to your constructor. Your AkamaiClient should then have a interface that you use as typehint in the __construct parameter.

  }

Missing newline.

  /**
   * {@inheritdoc}
   */
  public function getTimeHint() {
    // @todo Create a configurable max timeout.
    return 4.00;
  }
  • Missing newline.
  • You like want to drop ::getTimeHint() and replace it with ::getRuntimeMeasurement() returning TRUE, this gives a huge benefit as the time hint becomes dynamically measured and thus the amount of invalidations fed to AkamaiPurger::invalidate() will increase over time based on real-world measurements.
  /**
   * {@inheritdoc}
   */
  public function invalidate(array $invalidations) {

If you want, you can override (see its docblock) ::routeTypeToMethod and route certain types to certain methods that you define, for example a invalidateTags, invalidateUrls and invalidateEverything. This allows you to have the most optimized implementation for each type.

    foreach ($invalidations as $invalidation) {
      $invalidation->setState(InvalidationInterface::PROCESSING);

The state PROCESSING has basically been created with Akamai in mind, since it means that objects can flow back to the queue in this state and be offered to ::invalidate() again later. Therefore you want to check for incoming objects that are already in state PROCESSING since those likely need a status check at Akamai. Another thing missing here is leveraging a feature I'm working on upstream: ::setProperty($key, $value) and ::getProperty($key), these will allow you to store akamai IDs within your invalidation object to later check for one on incoming objects that are in state PROCESSING.

      $invalidation_type = $invalidation->getPluginId();
      switch ($invalidation_type) {
        case 'url':
          $urls_to_clear[] = $invalidation;
          break;
        // @todo implement other invalidation types

See note on ::routeTypeToMethod().

      }
    }
    $this->client->purgeUrls($urls_to_clear);

This is odd, you're feeding URLs to you're backend API but there's nothing checking what happened. This is a problem as you aren't setting the outgoing states of each invalidation object that you processed, outgoing states that make sense are:

  • $invalidation->setState(InvalidationInterface::PROCESSING); (for getting it back later)
  • $invalidation->setState(InvalidationInterface::SUCCEEDED); (deleted from queue)
  • $invalidation->setState(InvalidationInterface::FAILED); (comes back later for reattempt)

  }

Missing newline.

}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment