Problem/Motivation

We are using the module for invalidating cached files and images in Cloudflare. It works correctly in these cases, but one scenario has not been considered: the derivative images that are generated when there are possibilities of multiple image styles. Those cases remain cached.

The module Varnish Image Purge, Varnish Purge submodule, implements this functionality, perhaps we can adapt this approach in the purge file module.

Proposed resolution

Implement a new function in purge_file.module that includes the image derivatives:

  • Check that the object file is a image object.
  • Get the different image styles and the uris for the object file.
  • Check if the image derivative exits to try to reduce the number of petitions to the API.
  • Add the image derivative URLs to the list of URLs that need to be purged

Configuration

  1. Allow selecting which images styles to purge. By default it must be empty.
  2. The configuration form must indicate the image styles will be always enqueued.

Logic

This is the proposed logic with some code examples of how it could work.

1) Initialize a list of invalidations classified by inmediate and queue:

$invalidations = [
  'inmediate' => [],
  'queue' => [],
];

2) All image styles must be added always to the queue as the number can be very high.
The rest of URLs can be classified with the currently configured group.

$url_workflow = $is_image_style ? 'queue' : $workflow;
$invalidations[$url_workflow][] = $invalidator_factory->get($invalidator, $url);

3) Iterate both type of invalidations and add them to the queue.

foreach (array_filter($invalidations) as $invalidation_type => $url_invalidations) {
    if ($invalidation_type === 'queue') {
      // Queue invalidation for any queue processor to process.
      // Example: The purge_processor_cron module.
      $queuer = \Drupal::service('purge.queuers')->get('purge_file_queuer');
      if ($queuer) {
        \Drupal::service('purge.queue')->add($queuer, $url_invalidations);
      }
    }
    else {
      // Immediate invalidation.
      $processor = \Drupal::service('purge.processors')->get('purge_file_immediate_processor');
      if ($processor) {
        \Drupal::service('purge.purgers')->invalidate($processor, $url_invalidations);
      }
    }
}

Issue fork purge_file-3455034

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

lpeidro created an issue. See original summary.

lpeidro’s picture

Issue summary: View changes
omarlopesino’s picture

This problem should have been fixed at 1.1.0 with this issue: https://www.drupal.org/project/purge_file/issues/3308665 . May you enable the wildcard option at the purge file configuration, and check if that solves the issue?

If that solves the problem, we could improve the documentation to explain how to solve problems with image style derivatives.

lpeidro’s picture

The wildcard functionality is not sufficient to purge the image files generated by image styles. In this case, the URLs of the derived images vary in their middle structure, so a wildcard at the end of the original image URL would not apply to the derived ones.

The derived images are not constituted as file entities, so when the file entity is deleted, the Styles module directly deletes all the files that have been generated that are derived images.

I have created a proposal that has a fundamental problem related to the number of image styles that may exist in an installation.

When there are many image styles, the system to check if they exist can take 2-3 seconds. This is because the check is done exclusively in the context of deleting the entity and by making a HEAD request to the image URL. If the image is cached and needs to be purged, it will return a 200 status; otherwise, it can be omitted since it does not exist in the cache. This check is done to avoid send unnecessary requests to the API.

Perhaps this could be solved by implementing queues, and there is an issue about this.

On the other hand, maybe is not so serious to send requests to the API asking to remove cache objects that does not exists.

Anyway, I think that the implementation of queues should be mandatory for this implementation, to avoid that in this border cases (sites with many Image Styles) can happen bugs.

dpi’s picture

Assigned: lpeidro » Unassigned

To me, it sounds like this is not within the scope of this project.

There should be a project dedicated to image derivatives, or Purge itself should support it, since it is a core feature.

jonhattan’s picture

Some thoughs:

1. Implement a wildcard purge based on the styles folder: `public://styles/*/filename-path` (not sure now but I think it may be generalized to use the default stream wrapper instead of hardcoding public://)

Note: wildcard purge is not available in all cache/cdn solutions, so it must be a configurable option and fallback to iterating all image styles.

2. I think asking to purge images in despite of they don't exists is better from a performance viewpoint, because a HEAD on inexistent resource in the cache will trigger a call to the backend... ending in a hit to the db server.

3. I think it should be a submodule and avoid mixing image specific stuff with file basic stuff. Perhaps

4. To check file is an image use `Image::isValid` as in:

$image_factory = \Drupal::service('image.factory');
$image = $image_factory->get($file->getFileUri());
if ($image->isValid()) {
 // ...
}
omarlopesino’s picture

Thanks for all your feedback.

I agree that ¡ purging additional URLs than the self URL is out of the main purpose of this module. However, it is a good idea start giving support to it as purging image style URLS is consequent to purging the original file URL. Removing only the original file may leave the files cache inconsistent (older image in not purged image styles, new image in new image styles).

I agree with the solutions proposed at #6. My only doubt is how to separate image style logic from 'purge file' logic. A submodule looks good, but most sites uses image styles. Maybe we can separate the logic by dispatching a hook that lets adding more paths based on the current file. What do you think?

omarlopesino’s picture

Issue summary: View changes
omarlopesino’s picture

Issue summary: View changes
omarlopesino’s picture

Issue summary: View changes
omarlopesino’s picture

Assigned: Unassigned » bryan toapanta

After internal dialogue, we have decided to go for a solution that:

  • Allows selecting which image styles wants to be purged.
  • Always enqueues image styles. As the number can't be huge, inmediate purge can't be considered.

There is a resume of the solution in the task description.

omarlopesino’s picture

Issue summary: View changes

bryan toapanta made their first commit to this issue’s fork.

omarlopesino’s picture

Status: Active » Needs review
omarlopesino’s picture

Status: Needs review » Needs work

I have reviewed it and put some comments. After those changes I think we can merge it.

omarlopesino’s picture

Status: Needs work » Fixed

Thanks everyone who have helped on this issue. It has been finally merged in 1.0.x and will be released soon.

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

Status: Fixed » Closed (fixed)

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