-
Notifications
You must be signed in to change notification settings - Fork 17
Feature persistent caching #42
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
base: main
Are you sure you want to change the base?
Feature persistent caching #42
Conversation
growthbook/growthbook.py
Outdated
@@ -248,19 +339,28 @@ async def _stop_session(self): | |||
|
|||
class FeatureRepository(object): | |||
def __init__(self) -> None: | |||
self.cache: AbstractFeatureCache = InMemoryFeatureCache() | |||
self.in_memory_cache: AbstractFeatureCache = InMemoryFeatureCache() |
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 will violate public interface of the class.
instead of squeezing more caches into single repo and forcing user to use (and setup) both, you can create another AbstractFeatureCache
class (and name it something like LayeredFeatureCache
) which should be able to combine as many caches user wants.
that aside I don't think that feature flag service needs multi-level cache, because flag should be as consistent as possible between processes and allowing multiple caches to serve data will make cache more variable.
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 agree that squeezing multiple caches directly into FeatureRepository isn't ideal. You're right, the LayeredFeatureCache approach is much cleaner and more flexible.
We've actually implemented LayeredFeatureCache as part of this. It allows us to combine different caching strategies (like in-memory and an external cache) under a single, consistent interface.
growthbook/growthbook.py
Outdated
self.cache: Dict[str, CacheEntry] = {} | ||
|
||
def _get_base_path(self) -> Path: | ||
base_path = Path("./GrowthBook-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.
not configurable? looks like general directory but only this class knows about it for some reason
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.
Done
growthbook/growthbook.py
Outdated
class FileFeatureCache(AbstractPersistentFeatureCache): | ||
def __init__(self, cache_file: str): | ||
self.cache_file = cache_file | ||
self.cache: Dict[str, CacheEntry] = {} |
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.
maybe use protected variables? otherwise someone might use them as public API and we will stuck with them forever.
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.
Done
growthbook/growthbook.py
Outdated
@@ -74,16 +91,14 @@ def set(self, key: str, value: Dict, ttl: int) -> None: | |||
def clear(self) -> None: | |||
pass | |||
|
|||
class AbstractPersistentFeatureCache(AbstractFeatureCache): | |||
@abstractmethod | |||
def load(self) -> None: |
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.
looks like implementation detail which could be hidden and called from constructor or other methods
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.
Done
…est_multiple_instances_get_updated_on_cache_expiry tests
# Conflicts: # growthbook/growthbook.py
This PR implements two-level caching for GrowthBook feature data in the Python SDK:
On initialization, GrowthBook loads features from persistent file-based cache (if available and not expired).
The loaded data is stored in the in-memory cache and used for feature evaluations.
No network request is made unless the cached data is expired or missing.