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
- Allow selecting which images styles to purge. By default it must be empty.
- 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
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
Comment #2
lpeidro commentedComment #3
omarlopesinoThis 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.
Comment #4
lpeidro commentedThe 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.
Comment #5
dpiTo 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.
Comment #6
jonhattanSome 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:
Comment #7
omarlopesinoThanks 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?
Comment #8
omarlopesinoComment #9
omarlopesinoComment #10
omarlopesinoComment #11
omarlopesinoAfter internal dialogue, we have decided to go for a solution that:
There is a resume of the solution in the task description.
Comment #12
omarlopesinoComment #15
bryan toapanta commentedImplemented the solution in the issue fork.
- Branch: https://git.drupalcode.org/issue/purge_file-3455034/-/commits/3455034-im...
- MR: https://git.drupalcode.org/project/purge_file/-/merge_requests/12
Comment #16
omarlopesinoComment #17
omarlopesinoI have reviewed it and put some comments. After those changes I think we can merge it.
Comment #19
omarlopesinoThanks everyone who have helped on this issue. It has been finally merged in 1.0.x and will be released soon.