Skip to content

Commit

Permalink
feat: allow bulk invalidation (#10)
Browse files Browse the repository at this point in the history
Invalidate cache entries as a soft alternative to deletion. This
will have a very similar effect but release some strain from the
Redis engine. The expired cache entries will be collected and evicted
when Redis decides it is best
  • Loading branch information
e0ipso committed Oct 1, 2018
1 parent 25938cc commit 2c2151e
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"bio": "Engineer and programmer focused on online applications.",
"public_repos": 67,
"public_gists": 35,
"followers": 88,
"followers": 90,
"following": 45,
"created_at": "2011-10-20T14:27:43Z",
"updated_at": "2018-06-22T10:20:03Z"
Expand Down Expand Up @@ -58,11 +58,11 @@
"email": null,
"hireable": null,
"bio": "Software architect with an interest in distributed systems and elegant solutions.",
"public_repos": 78,
"public_repos": 80,
"public_gists": 38,
"followers": 50,
"followers": 51,
"following": 12,
"created_at": "2010-10-20T16:40:28Z",
"updated_at": "2018-07-25T21:18:08Z"
"updated_at": "2018-09-28T00:25:10Z"
}
]
28 changes: 27 additions & 1 deletion __tests__/functionals.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const generateTest = (redis, numItems) => () => {
)
);

expect.assertions(12);
expect.assertions(14);
return new Promise((resolve, reject) => {
redis.on('ready', resolve);
redis.on('error', reject);
Expand Down Expand Up @@ -101,6 +101,32 @@ const generateTest = (redis, numItems) => () => {
.then(res => {
// There is the item tagged with 'tag_1' and 'foo'.
expect(res).toEqual(['ipsum']);
})
.then(() => {
const rt = redis.tags(['tag_1']);
// Set very high TTLs on all items.
return Promise.resolve()
.then(() => rt.bulk((k, rt) => rt.store.expire(k, 999999999999)))
.then(() => rt.bulk((k, rt) => rt.store.ttl(k)));
})
.then(res => {
const allPositive: (Array<number>) => boolean = numbers =>
numbers.reduce((carry, ttl) => carry && ttl > 0, true);
// Make sure the TTLs are positive.
expect(allPositive(res)).toBe(true);
})
.then(() => {
const rt = redis.tags(['tag_1']);
// Invalidate all the entries of the tag and then check the TTLs.
return Promise.resolve()
.then(() => rt.invalidateWithTags())
.then(() => rt.bulk((k, rt) => rt.store.ttl(k)));
})
.then(res => {
const allNegative: (Array<number>) => boolean = numbers =>
numbers.reduce((carry, ttl) => carry && ttl <= 0, true);
// Make sure the TTLs are negative.
expect(allNegative(res)).toBe(true);
});
};

Expand Down
34 changes: 34 additions & 0 deletions src/RedisTaggedCache.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const { map: promiseMap } = require('bluebird');
const TaggedCache = require('./TaggedCache');

type TagRefs = Array<string>;
type Operation<T = void> = (string, TaggedCache) => Promise<T>;

class RedisTaggedCache extends TaggedCache {
/**
Expand Down Expand Up @@ -104,6 +105,39 @@ class RedisTaggedCache extends TaggedCache {
});
}

/**
* Bulk operation on tagged entries.
*
* @param {Operation} operation
* The operation to perform on each individual item.
* @param {number} pageSize
* The number of operations to execute at once. Empty to execute all.
*
* @return {Promise<[any]>}
* Resolves the result of the individual operations.
*/
bulk<T>(
operation: Operation<T>,
pageSize: number = Infinity
): Promise<Array<T>> {
return this.fetchTaggedKeysByTag()
.then(this.fetchTaggedKeys.bind(this))
.then(keys =>
promiseMap(keys, key => operation(key, this), { concurrency: pageSize })
);
}

/**
* Sets all the tagged entries to expire so they can be evicted by Redis.
*
* @return {Pr}
*/
invalidateWithTags(): Promise<Array<void>> {
const invalidate: Operation<void> = (key, tc) =>
tc.store.expire(key, 0).then(() => {});
return this.bulk(invalidate);
}

/**
* Lists all the entries for the provided tags.
*
Expand Down

0 comments on commit 2c2151e

Please sign in to comment.