-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
Introduce MetadataValidators to test arbitrary metadata for freshness. #15692
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Added test for ResourceInterfaceValidator ConfigCache::isFresh: Stop validation as soon as we found a supporting validator
The PR header says BC break yes / deprecations no. Is that correct? |
public function supports($metadata); | ||
|
||
public function isFresh($metadata, $timestamp); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing docs for those 2 methods
* | ||
* @author Matthias Pigulla <mp@webfactory.de> | ||
*/ | ||
class ValidatorConfigCacheFactory implements ConfigCacheFactoryInterface |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why creating a whole new config cache factory given adding validators to the old one is doable without BC break ? (But will prevent the deprecation due to https://github.com/symfony/symfony/pull/15692/files#diff-9f40590069e1fa6582e56bcea49e09a4R77)
Will the ConfigCacheFactory
trigger a deprecation saying to use the new ValidatorConfigCacheFactory
instead ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For BC reasons, the Router
and Translator
need to create a ConfigCacheFactory
themselves if none is injected. If that factory comes without the default ResourceInterfaceValidator
, they'd have to add one themselves and that would cause unnecessary dependencies. Having a default ResourceInterfaceValidator
in ConfigCacheFactory
would be weird as well.
So this way, use a ConfigCacheFactory
if you don't care about special validations and you'll get the same behaviour as in the past.
Use a ValidatorConfigCacheFactory if you care about special validations or if you get the instance injected anyway and don't care about the hassle of setting it up.
…and unlikely to disappear in the future
This may have worked in the past, but was based on assumptions how the cache was implemented. You cannot dump a cache in prod and then expect it to be fresh or not when switching back to dev. A useful test would: 1. Use a mock loader to detect reloads 2. In prod: Use a Translator to prime the cache; try again with another instance and see that the cache is used 3. In dev: Use a Translator to prime the cache; add an "always stale" resource; try again with another instance and see that the cache is refreshed.
…e cache works internally
…e a rich man already
* The first MetadataValidator that supports a given resource is considered authoritative. | ||
* Resources with no matching MetadataValidators will silently be ignored and considered fresh. | ||
* | ||
* This method <em>does not</em> take the debug flag into consideration: Whether or not a cache |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this looks weird to me. We need to take the debug flag into account
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like to make that a decision of the client (the ConfigCacheFactory). In production, it may skip all freshness checks or use a special set of Validators only.
Then, the cache itself would not need to know about debug
at all.
…in the constructor. That way, we can keep the isFresh() method and get away without deprecations.
* | ||
* @author Benjamin Klotz <bk@webfactory.de> | ||
*/ | ||
interface MetadataValidatorInterface |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure MetadataValidator is the best name. This is more a resource checker than a validator
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm open for naming suggestions.
CacheChecker
CacheMetadataChecker
MetadataChecker
ResourceChecker
ResourceMetadataChecker
...?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would say ResourceChecker
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ResourceCheckerInterface, that is?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for the interface, yes
as discussed in #15719, I think we should keep a new ResourceInterface for resources instead of using |
Maybe I have a completely wrong picture of what the transition path for such changes must look like. For example, the MessageCatalogueInterface is This is why I am trying to clean up the non- But if you can show me the right way to introduce a new interface for resources, I'd be glad to give it a try. |
What about this plan:
We'll end up with ResourceInterface containing only __toString() in 3.0. Users implementing ResourceInterface will get a deprecation notice and can either switch to the new interface (no change beyond changing the "implements" list) or add a custom ResourceChecker to resolve it. I acknowledge that @stof is in favor of having the new interface extend \Serializable as well, but I am not sure if that is possible in a BC way and still think that technically it is not necessary (i. e. should not stop us from getting all the rest). |
* Add priorities so that new custom ResourceCheckers can be run first * Provide a default ResourceChecker with a very low priority that will validate through ResourceInterface::isFresh() but triggers a deprecation warning. * Add a new interface that extends ResourceInterface and contains the isFresh() method. * Add a ResourceChecker for this interface with a slightly higher priority and without deprecation warning. * Make FileResource et. al. implement the new interface. * Deprecate ResourceInterface::isFresh() but keep that method in the new interface subclass.
I have implemented the above plan in #15738 and would like to close this PR in favor of it. (I did not open this PR myself so I cannot close it.) |
@bnw could you please close this? |
…pdude) This PR was squashed before being merged into the 2.8 branch (closes #15738). Discussion ---------- Implement service-based Resource (cache) validation | Q | A | ------------- | --- | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | yes | Tests pass? | yes | Fixed tickets | #7230, #15692, #7782 | License | MIT | Doc PR | symfony/symfony-docs#5136 ### Overview Currently, any metadata passed to `ConfigCache` (namely implementations of `ResourceInterface`) is serialized to disk. When the `ConfigCache` is validated, the metadata is unserialized and queried through `ResourceInterface::isFresh()` to determine whether the cache is fresh. That way, `ResourceInterface` implementations cannot interact with services, for example a database connection. This PR introduces the new concept of `ResourceCheckers`. Services implementing `ResourceCheckerInterface` can be tagged as `config_cache.resource_checker` with an optional priority. Clients that wish to use `ConfigCache` can then obtain an instance from the `config_cache_factory` service (which implements `ConfigCacheFactoryInterface`). The factory will take care of injecting resource checkers into the `ConfigCache` instance so that they can be used for cache validation. Checking cache metadata is easy for `ResourceCheckers`: * First, the `ResourceCheckerInterface::supports()` implementation is passed the metadata object in question. If the checker cannot handle the type of resource passed, `supports()` should return `false`. * Otherwise, the `ResourceCheckerInterface::isFresh()` method will be called and given the resource as well as the timestamp at which the cache was initialized. If that method returns `false`, the cache is considered stale. If it returns `true`, the resource is considered unchanged and will *not* be passed to any additional checkers. ### BC and migration path This PR does not (intend to) break BC but it comes with deprecations. The main reason is that `ResourceInterface` contains an `isFresh()` method that does not make sense in the general case of resources. Thus, `ResourceInterface::isFresh()` is marked as deprecated and should be removed in Symfony 3.0. Resource implementations that can (or wish to) be validated in that simple manner can implement the `SelfCheckingResourceInterface` sub-interface that still contains (and will keep) the `isFresh()` method. The change should be as simple as changing the `extends` list. Apart from that, `ResourceInterface` will be kept as the base interface for resource implementations. It is used in several `@api` interfaces and thus cannot easily be substituted. For the Symfony 2.x series, a `BCResourceInterfaceChecker` will be kept that performs validation through `ResourceInterface::isFresh()` but will trigger a deprecation warning. The remedy is to either implement a custom ResourceChecker with a priority higher than -1000; or to switch to the aforementioned `SelfCheckingResourceInterface` which is used at a priority of -990 (without deprecation warning). The `ConfigCache` and `ConfigCacheFactory` classes can be used as previously but do not feature checker-based cache validation. ### Outlook and closing remarks: This PR supersedes #7230, #15692 and works at least in parts towards the goal of #7176. The `ResourceCheckerInterface`, `...ConfigCache` and `...ConfigCacheFactory` no longer need to be aware of the `debug` flag. The different validation rules applied previously are now just a matter of `ResourceChecker` configuration (i. e. "no checkers" in `prod`). It might be possible to remove the `debug` flag from Symfony's `Router` and/or `Translator` classes in the future as well because it was only passed on to the `ConfigCache` there. Commits ------- 20d3722 Implement service-based Resource (cache) validation
This PR implements the idea discussed here: https://github.com/symfony/AsseticBundle/issues/168#issuecomment-13608074
Idea
Currently, any metadata that is passed to ConfigCache (namely implementations of ResourceInterface) is serialized to disk. Upon freshness check, it is unserialized and then asked, whether it is fresh.
The metadata has no chance to interact with any services, allowing only for very basic freshness checks.
With this PR, metadata no longer needs to implement the check for freshness itself. Instead, the ConfigCache::isFresh gets handed an array of MetadataValidator that take over the job of checking for freshness.
Each validator supports certain types of metadata. The implementations of ResourceInterface are now only a special type of metadata, that is validated using the ResourceInterfaceValidator.
In most cases, the ConfigCache should be used via the ConfigCacheFactory. I added a config_cache_factory service to which one can add validators via tagged services.
BC
Calling ConfigCache::isFresh without arguments is now deprecated.
Using ConfigCacheFactory without adding validators is deprecated.
However, both are still supported and yield the same results as before.