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
Delete cache entries older than max age #16
Conversation
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.
Could you also add a test to make sure it removes the old item?
Could you please propose how I would do that? |
Managed to get a working test for this. |
You can just check if the size of the cache is 0 after the expired time. Not necessary to override the delete method. |
No - because the cache is repopulated by virtue of the second call - with every call the |
Any idea when this PR will be released? Sounds like something we want to fix. |
@SamVerschueren @keithamus Are you two in a deadlock or what's going on? If there is really a memory leak, fixing it would be important, no? I'm about to use this in production in several parts of my infrastructure, so I got a little worried stumbling on this issue by accident... |
@0x80 I dont think we're in a deadlock. The PR has tests, and I've explained why those tests are what is needed and cannot be simplified. Happy to take more feedback from @SamVerschueren or @sindresorhus about what is needed to get this merged. If you're about to deploy this to production - you could always publish a version on your own namespace that includes this patch. |
@keithamus I will do that then. If it's hard or impossible to improve the tests, and it won't hurt to merge this, then I hope @SamVerschueren or someone can approve this PR. The last thing a memoization lib needs is a memory leak... 😄 |
I don't see how this fixes the problem though? The I think that a proper fix would cover the following test case: test('maxAge option deletes old items', async t => {
const f = () => 'foobar';
const cache = new Map();
const memoized = m(f, {maxAge: 100, cache});
t.is(memoized(1), 'foobar');
t.is(cache.has(1), true);
await delay(50);
t.is(cache.has(1), true);
await delay(50);
t.is(cache.has(1), false);
}); |
@LinusU if deletions were observable outside of calls to the memoized function as per your test case that would add a lot of complexity to this library which Im unsure is necessary. Adding for e.g. a |
This would be the only way to solve #14 though? Since the problem that that issue raises is that any cached value will stay in the cache until a new value replaces it. This is an issue if you e.g. are caching web fetches, but only want to cache them for 5 minutes. If you at some point make 5000 different requests, for some domains that you will never access again, those 5000 responses will now be stored in memory until the process is terminated. Did you understand what I meant with this?
As far as I can see, the patch that you have proposed doesn't change the behaviour of the module in any way. By extension, it also doesn't address the issue raised in #14. |
I understand this. I think in these instances it may be preferable to manually
I did. While calling
|
I agree with @LinusU that it does not solve #14 and it only helps when the new call fails like you mention @keithamus. Think the changes make sense for that part. |
This is good 👍 |
I've added an additional test to explicitly cover the case of a function throwing and the cache still being deleted. |
@keithamus Thank you and sorry for the slow reply. I've released it as a patch version. |
Related to #14 although it might not fix it explicitly.
This explicitly calls
delete()
if the max age has passed, so that if passing a caching object that is maybe different toMap
then it doesn't rely onset()
in order to actually remove old entries.This also fixes a bug where if a subsequent call to
fn
may throw an error (even if the original call did not - perhaps because some side-effect has changed, e.g. a filesystem - causingfn
to now throw) - then the.set
was never called and so older entries would remain without ever being explicitly cleared up.