Skip to content
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

CacheService may try to write value for deleted key #41

Closed
Zsar opened this issue Jul 5, 2022 · 2 comments · Fixed by #45
Closed

CacheService may try to write value for deleted key #41

Zsar opened this issue Jul 5, 2022 · 2 comments · Fixed by #45
Assignees

Comments

@Zsar
Copy link

Zsar commented Jul 5, 2022

Currently the "CacheService" does not perform the service of dropping outdated keys. Instead this must happen from the outside via invalidate. This means that keys may spontaneously be deleted silently and at any time.

return this._cacheContainer[key][1] = Promise.resolve(object); then fails because this._cacheContainer[key] is undefined.

Workaround: Always optional-chain.

Proper solution: Let the CacheService do the dropping, such that it may handle pending replies to dropped keys appropriately.

Design issue: How do we handle responses which only arrive after their key has already timed out. Either/or:

  1. What we actually want to cache is values, not keys. We should TTL the values, not the keys. Only when the key is written to should TTL start counting down for it.
  2. When a key times out before the value is written, discard the write (and emit a warning, I guess): This cache is not properly configured to handle the response times encountered, so they will never be cached.

... I prefer 1). @mreiche : Opinions?

@Zsar Zsar self-assigned this Jul 5, 2022
@mreiche
Copy link
Contributor

mreiche commented Jul 5, 2022

Fact is, the CacheService doesn't invalidate the outdated keys by its own, that is right. The documentation should be more clear here that you should implement your "garbage collector" on your own like that.

window.setInterval(() => {
    this._cacheService.invalidate(this._cacheService.outdatedKeys);
}, 10000);
  1. What we actually want to cache is values, not keys. We should TTL the values, not the keys. Only when the key is written to should TTL start counting down for it.

I dont know what you mean. This is a key-value-store where you only can TTL the key.

  1. When a key times out before the value is written, discard the write (and emit a warning, I guess): This cache is not properly configured to handle the response times encountered, so they will never be cached.

A write always refreshes the key TTL.
There is only one real issue for a race condition, when the loading callback takes too long.

this._cacheContainer[key] = [
    now,
    loadingFunction().then(object=>{
        return this._cacheContainer[key][1] = Promise.resolve(object);
    })
];

when the loadingFunction() takes more than the cacheTtlSeconds, the key could be deleted in the meantime and this._cacheContainer[key] became undefined. In this case, the better option should be to write:

this._cacheContainer[key] = [
    now,
    loadingFunction().then(object=>{
        const now = (Date.now()/1000);
        return this._cacheContainer[key] = [now, Promise.resolve(object)];
    })
];

That should fix it.

Opinions?

We should have tests for that.

@Zsar
Copy link
Author

Zsar commented Jul 5, 2022

Mmh. Maybe I should demonstrate... created #42 .
... If the TTL is lower than the time to answer, then TTL-ing the key will result in never receiving it. So I figure, maybe we'd better TTL the value.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment