Skip to content

Commit dbc26f1

Browse files
fix(cache): remove uninvalidate as it can undo invalidation in case of subsequent get (#2250)
* fix(cache): remove uninvalidate as it can undo invalidation in case of immediate get GH-2249 * fix(cache): remove uninvalidate function from cache service GH-2249 * feat(cache): add a few missing lines for a test case GH-2249
1 parent 5b0208c commit dbc26f1

File tree

7 files changed

+60
-48
lines changed

7 files changed

+60
-48
lines changed

packages/cache/src/__tests__/acceptance/cache-repository.mixin.acceptance.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {setupEnv} from '../helpers';
1111
import {repoTestBuilder} from '../helpers/test-builder';
1212

1313
dotenv.config();
14-
const DEFAULT_TIMEOUT = 5000;
14+
const DEFAULT_TIMEOUT = 15000;
1515

1616
describe('CachedRepository: Acceptance', () => {
1717
let app: TestApp;
@@ -33,6 +33,8 @@ describe('CachedRepository: Acceptance', () => {
3333
if (!process.env.REDIS_HOST || !process.env.REDIS_PORT) {
3434
// eslint-disable-next-line @typescript-eslint/no-invalid-this
3535
this.skip();
36+
} else {
37+
mochaContext.timeout(DEFAULT_TIMEOUT);
3638
}
3739
});
3840
beforeEach(async () => {
@@ -87,11 +89,6 @@ describe('CachedRepository: Acceptance', () => {
8789
describe(testSuite.title, () => {
8890
testSuite.tests.forEach(test => {
8991
it(test.title, async function () {
90-
if (test.timeout) {
91-
mochaContext.timeout(test.timeout);
92-
} else {
93-
mochaContext.timeout(DEFAULT_TIMEOUT);
94-
}
9592
await test.test(
9693
repo,
9794
mockData,
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1+
export * from './test-2.model';
12
export * from './test.model';
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import {Entity, model, property} from '@loopback/repository';
2+
3+
@model()
4+
export class Test2 extends Entity {
5+
@property({
6+
type: 'number',
7+
id: true,
8+
})
9+
id: number;
10+
@property({
11+
type: 'string',
12+
})
13+
name: string;
14+
constructor(data?: Partial<Test2>) {
15+
super(data);
16+
}
17+
}
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
1-
import {DefaultCrudRepository, juggler} from '@loopback/repository';
2-
import {Test} from '../models';
31
import {inject} from '@loopback/core';
2+
import {DefaultCrudRepository, juggler} from '@loopback/repository';
43
import {CacheMixin} from '../../../mixins';
4+
import {Test2} from '../models';
55

66
export class Test2WithMixinRepository extends CacheMixin(
7-
DefaultCrudRepository<Test, number, {}>,
7+
DefaultCrudRepository<Test2, number, {}>,
88
{
99
invalidationTags: ['TestTag', 'Test2Tag'],
1010
cachedItemTags: ['Test2Tag'],
1111
},
1212
) {
1313
cacheIdentifier = 'testRepo2';
1414
constructor(@inject('datasources.memorydb2') dataSource: juggler.DataSource) {
15-
super(Test, dataSource);
15+
super(Test2, dataSource);
1616
}
1717
}

packages/cache/src/__tests__/helpers/test-builder.ts

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ type TestCase = {
1313
secondRepo?: DefaultCrudRepository<Test, number, {}>,
1414
tick?: TickPromise,
1515
) => Promise<void>;
16-
timeout?: 3000;
1716
};
1817

1918
type TestSuite = {
@@ -170,7 +169,6 @@ export function repoTestBuilder(
170169
// one call for value and one for insertion time
171170
expect(cacheStoreSetSpy.callCount).to.equal(4);
172171
},
173-
timeout: 3000,
174172
},
175173
],
176174
},
@@ -375,7 +373,6 @@ export function repoTestBuilder(
375373
// one call for value and one for insertion time
376374
expect(cacheStoreSetSpy.callCount).to.equal(4);
377375
},
378-
timeout: 3000,
379376
},
380377
],
381378
},
@@ -673,6 +670,34 @@ export function repoTestBuilder(
673670
expect(cacheStoreSetSpy.callCount).to.equal(4);
674671
},
675672
},
673+
{
674+
title:
675+
'should invalidate cache after updateById, and subsequent get with different argument should not effect this invalidation',
676+
async test(
677+
repo: DefaultCrudRepository<Test, number, {}>,
678+
mockData: DataObject<Test>[],
679+
cacheStoreGetSpy: sinon.SinonSpy,
680+
cacheStoreSetSpy: sinon.SinonSpy,
681+
secondRepo?: DefaultCrudRepository<Test, number, {}>,
682+
) {
683+
const existing1 = await repo.findById(1);
684+
await flushPromises();
685+
expect(existing1).to.match(mockData[0]);
686+
const existing2 = await repo.findById(2);
687+
await flushPromises();
688+
expect(existing2).to.match(mockData[1]);
689+
await repo.updateById(1, {name: 'test-new-1'});
690+
await flushPromises();
691+
await repo.updateById(2, {name: 'test-new-2'});
692+
await flushPromises();
693+
const updatedLast = await repo.findById(2);
694+
await flushPromises();
695+
const updatedFirst = await repo.findById(1);
696+
await flushPromises();
697+
expect(updatedLast).to.match({id: 2, name: 'test-new-2'});
698+
expect(updatedFirst).to.match({id: 1, name: 'test-new-1'});
699+
},
700+
},
676701
{
677702
title: 'should invalidate cache across repositories',
678703
async test(

packages/cache/src/__tests__/integration/cache-repository.mixin.integration.ts

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,6 @@ describe('CachedRepository: Integration', () => {
2727
let cacheStoreGetSpy: sinon.SinonSpy;
2828
let cacheStoreSetSpy: sinon.SinonSpy;
2929
let clock: sinon.SinonFakeTimers | undefined = undefined;
30-
let mochaContext: Mocha.Context;
31-
32-
before(function () {
33-
// eslint-disable-next-line @typescript-eslint/no-invalid-this, @typescript-eslint/no-this-alias
34-
mochaContext = this;
35-
});
3630

3731
beforeEach(async () => {
3832
setupEnv();
@@ -72,9 +66,6 @@ describe('CachedRepository: Integration', () => {
7266
describe(testSuite.title, () => {
7367
testSuite.tests.forEach(test => {
7468
it(test.title, async function () {
75-
if (test.timeout) {
76-
mochaContext.timeout(test.timeout);
77-
}
7869
await test.test(
7970
repo,
8071
mockData,

packages/cache/src/services/cache.service.ts

Lines changed: 7 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -161,11 +161,13 @@ export class CacheService implements ICacheService {
161161
}
162162
}
163163
const result = await fn(...args);
164-
// eslint-disable-next-line @typescript-eslint/no-floating-promises
165-
this.saveInCache(prefix, key, options?.tags ?? [], result, cacheOptions)
166-
.catch(err => this.logger.error(err.message))
167-
// to make sure new calls for same prefix or tags are not invalidated
168-
.then(_ => this.uninvalidate(prefix, options?.tags));
164+
this.saveInCache(
165+
prefix,
166+
key,
167+
options?.tags ?? [],
168+
result,
169+
cacheOptions,
170+
).catch(err => this.logger.error(err.message));
169171
return result;
170172
}
171173

@@ -202,27 +204,6 @@ export class CacheService implements ICacheService {
202204
await this.store.setMany([prefixDeletion, ...tagDeletions]);
203205
}
204206

205-
/**
206-
* This function removes invalidatations of cache entries based on a given prefix and tags.
207-
* @param {string} prefix - The `prefix` parameter is a string that is used to identify a group of
208-
* items that need to be uninvalidated.
209-
* @param {string[]} [tags] - The `tags` parameter in the `uninvalidate` method is an optional
210-
* parameter of type `string[]`. It is an array of strings that represent tags that were invalidated. If
211-
* this parameter is provided when calling the method, the corresponding tags will be uninvalidated along
212-
* with the specified prefix. If the `
213-
*/
214-
private async uninvalidate(prefix: string, tags?: string[]): Promise<void> {
215-
const prefixDeletion = this.invalidatePrefix(prefix);
216-
let tagDeletions: [string, number, number][] = [];
217-
if (tags) {
218-
tagDeletions = this.invalidateTags(tags);
219-
}
220-
await this.store.deleteMany([
221-
prefixDeletion[0],
222-
...tagDeletions.map(record => record[0]),
223-
]);
224-
}
225-
226207
private invalidatePrefix(prefix: string): [string, number, number] {
227208
const deletionKey = this.buildKey(this.deletionMarkerPrefix, prefix);
228209
return [deletionKey, Date.now(), this.configuration.ttl];

0 commit comments

Comments
 (0)