Commit graph

6 commits

Author SHA1 Message Date
Dan Duvall
a824da0f34 Support stale cached settings for failover
Require a `CacheableSource` implementation to signal whether stale
settings may be served from the cache by implementing an
`allowsStaleLoad()` method. This will be useful for sources (e.g. etcd)
that expect some degree of unavailability and failover during
unavailability is desired.

In order to support stale results, `CachedSource` sets cache items with
an indefinite TTL but uses the computed expiry timestamp in the envelope
to consider whether the item is considered expired as opposed to a true
miss where the item is malformed or not present in the cache store.  If
a `SettingsBuilderException` is thrown during the source's `load()`
method but the cache check was not a real miss, the stale cached results
are returned.

Note there is currently no pruning of cache items so it is advised that
`CacheableSource` implementations for which stale loads are allowed also
implement an immutable `getHashKey()` based on constructor arguments.

Bug: T296771
Change-Id: Ida0698a237dc0939230799700b6f54956f033d50
2022-01-21 13:31:09 -08:00
daniel
da99bcd6aa SettingsBuilder: load settings recursively
Allows settings files to include other settings files.

Change-Id: Ieab7def1ada8b255e60c58927850a58e18309f6e
2022-01-18 21:51:35 +01:00
Dan Duvall
9fb695d75c Refactor cache TTL for SettingsBuilder sources
Move cache TTL from `CachedSource` into the `CacheableSource` interface,
allowing each source to define a TTL most appropriate to its own
settings loading implementation.

Fix bug where `generation` time was computed incorrectly by `CachedSource`.

Include tests to exercise all `CachedSource` interactions with
`CacheInterface` and `CacheableSource`.

Bug: T296771
Change-Id: I97c42cf6ca716516c32104de25245aa21ec110e4
2021-12-02 09:53:46 -08:00
Dan Duvall
d83a7bcd09 Cache loading of SettingsBuilder sources
The `SettingsBuilder` now accepts a PSR-16 cache interface with which to
store and query settings before attempting to load from each source. By
default, no cache is used, but any object that implements the
`Psr\SimpleCache\CacheInterface` may be provided to the constructor.

An explicit dependency on "psr/simple-cache" has been added to
`composer.json`. Note that this dependency already existed in vendor
albeit it as a transitive one.

An APCu based `SharedMemoryCache` adapter is provided as a canonical
PSR-16 compliant interface for production use.

Sources are now queued by the `SettingsBuilder` when calling `load()`.
If a cache interface has been provided, and the source is considered
cacheable (implements `CacheableSource`), then it is wrapped as a
`CachedSource` which will query the cache first before loading from the
wrapped source.

Cache stampedes are mitigated using probabilistic early expiry. The
implementation for this was partially based on symfony/cache-contract
source code but also from the Wikipedia article and paper referenced
therein.

See https://en.wikipedia.org/wiki/Cache_stampede#Probabilistic_early_expiration

Bug: T294748
Change-Id: I52ab3899731546876ee58265bd4a1927886746dc
2021-11-29 12:54:59 -08:00
Petr Pchelko
120ef51cbf SettingsBuilder: Add YAML file format.
If php-yaml extension in installed, use that. Otherwise
we fallback to symfony Yaml parser.

php-yaml is about 20 times faster then symfony, for default-settings.yaml
it will take PHP-yaml 6ms to load it vs 100ms for symfony. But given
that the result will be cached, it's better not to bring in
a required native dependency.

Bug: T294751
Change-Id: I3ffde926c3f264cacf39810ff7bd338c9f78823d
2021-11-29 09:27:20 -08:00
Dan Duvall
9a4af25664 Introduced settings sources and formats
A `SettingsSource` is meant to represent any kind of local or remote
store from which settings can be read, be this a local file, remote URL,
database, etc. It is concerned with reading in (and possibly decoding)
settings data, and computing a consistent hash key that may be used in
caching.

A `SettingsFormat` is meant to detect supported file types and/or decode
source contents into settings arrays. As of now, JSON is the only
supported format but others may be implemented.

`FileSource` is the first source implementation, with its default format
being JSON, meant to read settings from local JSON files.

`ArraySource` is mostly useful for testing using array literals.

Refactored `SettingsBuilder` methods to use the new source abstractions.

Bug: T295499
Change-Id: If7869609c4ad1ccd0894d5ba358f885007168972
2021-11-15 14:07:59 -08:00