-
Notifications
You must be signed in to change notification settings - Fork 4k
Add on_release to st.cache_resource. #13439
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
Replace the TTLCache in ResourceCache with a TTLCleanupCache. Add on_release to the st.cache_resource API, and plumb it through to the TTLCleanupCache. Update st.cache_resource.clear_all to clear the cache directly instead of just GCing it to ensure release functions are called. Implements feature request in #8764 .
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
✅ PR preview is ready!
|
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.
Pull request overview
This PR adds an on_release callback parameter to st.cache_resource, allowing users to specify cleanup functions that are automatically called when cached resources are removed from the cache. This implements feature request #8674.
Key Changes
- Added
on_releaseparameter to thest.cache_resourceAPI with comprehensive documentation - Replaced
TTLCachewithTTLCleanupCacheinResourceCacheto support release callbacks - Updated
ResourceCaches.clear_all()to explicitly callclear()on each cache before removing them, ensuring release functions are invoked
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| lib/streamlit/runtime/caching/cache_resource_api.py | Added on_release parameter throughout the caching layers, updated imports to use TTLCleanupCache, modified clear_all() to trigger callbacks, and added comprehensive documentation |
| lib/tests/streamlit/runtime/caching/cache_resource_api_test.py | Added test_on_release_fires() to verify callbacks are invoked on cache eviction and explicit clearing |
📉 Frontend coverage change detectedThe frontend unit test (vitest) coverage has decreased by 0.0000%
✅ Coverage change is within normal range. |
lukasmasuch
left a comment
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.
LGTM 👍
| for cache in self._function_caches.values(): | ||
| cache.clear() |
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.
nitpick: Maybe add a brief comment here that calling clear explicitly is required to trigger the on-release hooks.
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.
This sent me down a rabbit hole, as I realized I hadn't checked the behavior when multiple items are being cleared and one throws an exception. Now, this is handled correctly, and has some test coverage.
| validate: ValidateFunc | None, | ||
| hash_funcs: HashFuncsDict | None = None, | ||
| show_time: bool = False, | ||
| on_release: OnRelease = _no_op_release, |
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.
nitpick: might be slightly more consistent if we support on_release: OnRelease | None = None here and just pass down the None value from the decorator and use on_release or _no_op_release in the initialization.
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.
Sure, Done.
| This is not used as a part of the cache key - meaning changes to this | ||
| function between script runs will not trigger a new resource being | ||
| generated. |
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.
suggestion: This note might be a bit misleading/inconsistent since - afaik - none of the cache configuration parameters are part of the cache key or trigger a cache regeneration. Maybe we can simplify this to just add a top-level note that changing cache configuration parameter will not invalidate the existing cached entries.
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.
max_entries and ttl are both part of the (function) cache key, and changes to these will invalidate cache entries.
While validate is in that if block, the invoked helper just checks to see if the Nonefulness has changed.
I'm happy to remove this, if you think it's just adding confusion.
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.
Oh, I didn't know that, but makes sense. I was looking at the cache key generated here which doesn't seem to be impacted:
| def _make_function_key(cache_type: CacheType, func: Callable[..., Any]) -> str: |
and the value key:
| def _make_value_key( |
I think its worth documenting, but maybe better to mention this in the ttl and max_entries docstrings that changing it invalidates the existing cache entries.
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.
Updated! Also noted that Pandas (and therefore this helper) treats unitless string TTLs as nanoseconds, which has caused confusion in the past.
Small style cleanup.
sfc-gh-jkinkead
left a comment
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.
Thanks for the quick review!
| for cache in self._function_caches.values(): | ||
| cache.clear() |
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.
This sent me down a rabbit hole, as I realized I hadn't checked the behavior when multiple items are being cleared and one throws an exception. Now, this is handled correctly, and has some test coverage.
| validate: ValidateFunc | None, | ||
| hash_funcs: HashFuncsDict | None = None, | ||
| show_time: bool = False, | ||
| on_release: OnRelease = _no_op_release, |
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.
Sure, Done.
| This is not used as a part of the cache key - meaning changes to this | ||
| function between script runs will not trigger a new resource being | ||
| generated. |
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.
max_entries and ttl are both part of the (function) cache key, and changes to these will invalidate cache entries.
While validate is in that if block, the invoked helper just checks to see if the Nonefulness has changed.
I'm happy to remove this, if you think it's just adding confusion.
|
@lukasmasuch - I'll likely merge by EOD. Feel free to add more comments if you have them, and I'll address in a follow-up if there are any! |
Fix typo. Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
Add note about default Pandas units on ttl, as this can be tricky.
Describe your changes
Replace the TTLCache in ResourceCache with a TTLCleanupCache.
Add on_release to the st.cache_resource API, and plumb it through to the TTLCleanupCache.
Update st.cache_resource.clear_all to clear the cache directly instead of just GCing it to ensure release functions are called.
Implements feature request in #8674 .
GitHub Issue Link (if applicable)
Testing Plan
Implemented.
Contribution License Agreement
By submitting this pull request you agree that all contributions to this project are made under the Apache 2.0 license.