medikoo / memoizee

Complete memoize/cache solution for JavaScript
ISC License
1.73k stars 61 forks source link

Fallback to the old cache #85

Closed SzybkiSasza closed 7 years ago

SzybkiSasza commented 7 years ago

I wanted to propose a new feature - as the library is able to react and invalidate the cache in the case of error thrown in memoized function, maybe implementing fallback behaviour would be something that would be useful?

Imagine the situation - we memoized the function that obtains some data over the network. After the cache got invalidated (e.g. by manual cleaning or reaching maxAge), next call threw an error. Can we use "old" cache data to be returned regardless of invalidation?

It can be implemented by passing a new flag to options, e.g. fallbackToOldValue or similar

We implemented similar behaviour using following code in the memoized function:

var cache = {};

function toBeMemoized(param) {
    return doRequest(param)
    .tap(data => {
        cache[param] = data;
    })
    .catch(err => {
        if (cache[param]) {
            logger.err(err, 'someError');
            return cache[param];
        }

        throw err;
    });
}
epayet commented 7 years ago

The memoized function has an internal cache, but it's not really publicly exposed. You're doing the same behavior here with the cache variable.

This was referenced on some issues before, and I made a PR (https://github.com/medikoo/memoizee/pull/72) to have a way to read from the cache. It works like this:

var memoized = memoize(myFunction);
memoized._get('foo'); // Cache is empty at the moment, so returns undefined
var result = memoized('foo');
var resultFromCache = memoized._get('foo'); // Something is in the cache for those parameters now
console.log(result == resultFromCache); // true

With this, you can have some logic around failures, and if it fails you can read from the cache, and serve a stale value.

try {
    memoized(params);
} catch(err) {
    if(memoized._has(params)) {
        console.log('Oops, something failed, but we were able to serve a stale value');
        return memoized._get(params);
    } else {
        // No stale cache to serve, rethrow the err :/
        throw err;
    }
}

You have to check that this works with promises as well, hopefully it would (the cache works a bit differently in async mode).

You will notice the prefix _ for those methods, it is on the public API method, see this comment: https://github.com/medikoo/memoizee/pull/72#discussion_r105609462

As you mentioned, it would be perfect if this logic was implemented by the library, with an option of some sort: fallbackToOldValue.

Hopefully, the V1 will take this into account.

medikoo commented 7 years ago

maybe implementing fallback behaviour would be something that would be useful?

This actually was discussed before, see -> https://github.com/medikoo/memoizee/issues/51#issuecomment-174465319. Unfortunately it's not that easy to implement with current design, but will be definitely addressed with V1

If that helps for now, you may resort to methods as proposed by @epayet

I'm going to close it, as it's duplicate of #51 which remains open until functionality is delivered. Thanks for report!