Cleanup Schema cache per request (#6126)
* remove enableSingleSchemaCache from test * clear schema cache per request
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -56,3 +56,6 @@ lib/
|
|||||||
|
|
||||||
# Folder created by FileSystemAdapter
|
# Folder created by FileSystemAdapter
|
||||||
/files
|
/files
|
||||||
|
|
||||||
|
# Redis Dump
|
||||||
|
dump.rdb
|
||||||
|
|||||||
@@ -172,16 +172,18 @@ describe_only(() => {
|
|||||||
let cacheAdapter;
|
let cacheAdapter;
|
||||||
let getSpy;
|
let getSpy;
|
||||||
let putSpy;
|
let putSpy;
|
||||||
|
let delSpy;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
cacheAdapter = new RedisCacheAdapter();
|
cacheAdapter = new RedisCacheAdapter();
|
||||||
await cacheAdapter.clear();
|
|
||||||
await reconfigureServer({
|
await reconfigureServer({
|
||||||
cacheAdapter,
|
cacheAdapter,
|
||||||
enableSingleSchemaCache: true,
|
|
||||||
});
|
});
|
||||||
|
await cacheAdapter.clear();
|
||||||
|
|
||||||
getSpy = spyOn(cacheAdapter, 'get').and.callThrough();
|
getSpy = spyOn(cacheAdapter, 'get').and.callThrough();
|
||||||
putSpy = spyOn(cacheAdapter, 'put').and.callThrough();
|
putSpy = spyOn(cacheAdapter, 'put').and.callThrough();
|
||||||
|
delSpy = spyOn(cacheAdapter, 'del').and.callThrough();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('test new object', async () => {
|
it('test new object', async () => {
|
||||||
@@ -189,7 +191,11 @@ describe_only(() => {
|
|||||||
object.set('foo', 'bar');
|
object.set('foo', 'bar');
|
||||||
await object.save();
|
await object.save();
|
||||||
expect(getSpy.calls.count()).toBe(3);
|
expect(getSpy.calls.count()).toBe(3);
|
||||||
expect(putSpy.calls.count()).toBe(2);
|
expect(putSpy.calls.count()).toBe(3);
|
||||||
|
expect(delSpy.calls.count()).toBe(1);
|
||||||
|
|
||||||
|
const keys = await cacheAdapter.getAllKeys();
|
||||||
|
expect(keys.length).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('test new object multiple fields', async () => {
|
it('test new object multiple fields', async () => {
|
||||||
@@ -202,7 +208,11 @@ describe_only(() => {
|
|||||||
});
|
});
|
||||||
await container.save();
|
await container.save();
|
||||||
expect(getSpy.calls.count()).toBe(3);
|
expect(getSpy.calls.count()).toBe(3);
|
||||||
expect(putSpy.calls.count()).toBe(2);
|
expect(putSpy.calls.count()).toBe(3);
|
||||||
|
expect(delSpy.calls.count()).toBe(1);
|
||||||
|
|
||||||
|
const keys = await cacheAdapter.getAllKeys();
|
||||||
|
expect(keys.length).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('test update existing fields', async () => {
|
it('test update existing fields', async () => {
|
||||||
@@ -216,7 +226,11 @@ describe_only(() => {
|
|||||||
object.set('foo', 'barz');
|
object.set('foo', 'barz');
|
||||||
await object.save();
|
await object.save();
|
||||||
expect(getSpy.calls.count()).toBe(3);
|
expect(getSpy.calls.count()).toBe(3);
|
||||||
expect(putSpy.calls.count()).toBe(0);
|
expect(putSpy.calls.count()).toBe(1);
|
||||||
|
expect(delSpy.calls.count()).toBe(2);
|
||||||
|
|
||||||
|
const keys = await cacheAdapter.getAllKeys();
|
||||||
|
expect(keys.length).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('test saveAll / destroyAll', async () => {
|
it('test saveAll / destroyAll', async () => {
|
||||||
@@ -234,14 +248,18 @@ describe_only(() => {
|
|||||||
}
|
}
|
||||||
await Parse.Object.saveAll(objects);
|
await Parse.Object.saveAll(objects);
|
||||||
expect(getSpy.calls.count()).toBe(21);
|
expect(getSpy.calls.count()).toBe(21);
|
||||||
expect(putSpy.calls.count()).toBe(10);
|
expect(putSpy.calls.count()).toBe(11);
|
||||||
|
|
||||||
getSpy.calls.reset();
|
getSpy.calls.reset();
|
||||||
putSpy.calls.reset();
|
putSpy.calls.reset();
|
||||||
|
|
||||||
await Parse.Object.destroyAll(objects);
|
await Parse.Object.destroyAll(objects);
|
||||||
expect(getSpy.calls.count()).toBe(11);
|
expect(getSpy.calls.count()).toBe(11);
|
||||||
expect(putSpy.calls.count()).toBe(0);
|
expect(putSpy.calls.count()).toBe(1);
|
||||||
|
expect(delSpy.calls.count()).toBe(3);
|
||||||
|
|
||||||
|
const keys = await cacheAdapter.getAllKeys();
|
||||||
|
expect(keys.length).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('test saveAll / destroyAll batch', async () => {
|
it('test saveAll / destroyAll batch', async () => {
|
||||||
@@ -259,14 +277,18 @@ describe_only(() => {
|
|||||||
}
|
}
|
||||||
await Parse.Object.saveAll(objects, { batchSize: 5 });
|
await Parse.Object.saveAll(objects, { batchSize: 5 });
|
||||||
expect(getSpy.calls.count()).toBe(22);
|
expect(getSpy.calls.count()).toBe(22);
|
||||||
expect(putSpy.calls.count()).toBe(5);
|
expect(putSpy.calls.count()).toBe(7);
|
||||||
|
|
||||||
getSpy.calls.reset();
|
getSpy.calls.reset();
|
||||||
putSpy.calls.reset();
|
putSpy.calls.reset();
|
||||||
|
|
||||||
await Parse.Object.destroyAll(objects, { batchSize: 5 });
|
await Parse.Object.destroyAll(objects, { batchSize: 5 });
|
||||||
expect(getSpy.calls.count()).toBe(12);
|
expect(getSpy.calls.count()).toBe(12);
|
||||||
expect(putSpy.calls.count()).toBe(0);
|
expect(putSpy.calls.count()).toBe(2);
|
||||||
|
expect(delSpy.calls.count()).toBe(5);
|
||||||
|
|
||||||
|
const keys = await cacheAdapter.getAllKeys();
|
||||||
|
expect(keys.length).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('test add new field to existing object', async () => {
|
it('test add new field to existing object', async () => {
|
||||||
@@ -280,7 +302,11 @@ describe_only(() => {
|
|||||||
object.set('new', 'barz');
|
object.set('new', 'barz');
|
||||||
await object.save();
|
await object.save();
|
||||||
expect(getSpy.calls.count()).toBe(3);
|
expect(getSpy.calls.count()).toBe(3);
|
||||||
expect(putSpy.calls.count()).toBe(1);
|
expect(putSpy.calls.count()).toBe(2);
|
||||||
|
expect(delSpy.calls.count()).toBe(2);
|
||||||
|
|
||||||
|
const keys = await cacheAdapter.getAllKeys();
|
||||||
|
expect(keys.length).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('test add multiple fields to existing object', async () => {
|
it('test add multiple fields to existing object', async () => {
|
||||||
@@ -300,7 +326,11 @@ describe_only(() => {
|
|||||||
});
|
});
|
||||||
await object.save();
|
await object.save();
|
||||||
expect(getSpy.calls.count()).toBe(3);
|
expect(getSpy.calls.count()).toBe(3);
|
||||||
expect(putSpy.calls.count()).toBe(1);
|
expect(putSpy.calls.count()).toBe(2);
|
||||||
|
expect(delSpy.calls.count()).toBe(2);
|
||||||
|
|
||||||
|
const keys = await cacheAdapter.getAllKeys();
|
||||||
|
expect(keys.length).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('test user', async () => {
|
it('test user', async () => {
|
||||||
@@ -310,7 +340,11 @@ describe_only(() => {
|
|||||||
await user.signUp();
|
await user.signUp();
|
||||||
|
|
||||||
expect(getSpy.calls.count()).toBe(8);
|
expect(getSpy.calls.count()).toBe(8);
|
||||||
expect(putSpy.calls.count()).toBe(1);
|
expect(putSpy.calls.count()).toBe(2);
|
||||||
|
expect(delSpy.calls.count()).toBe(1);
|
||||||
|
|
||||||
|
const keys = await cacheAdapter.getAllKeys();
|
||||||
|
expect(keys.length).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('test allowClientCreation false', async () => {
|
it('test allowClientCreation false', async () => {
|
||||||
@@ -318,16 +352,18 @@ describe_only(() => {
|
|||||||
await object.save();
|
await object.save();
|
||||||
await reconfigureServer({
|
await reconfigureServer({
|
||||||
cacheAdapter,
|
cacheAdapter,
|
||||||
enableSingleSchemaCache: true,
|
|
||||||
allowClientClassCreation: false,
|
allowClientClassCreation: false,
|
||||||
});
|
});
|
||||||
|
await cacheAdapter.clear();
|
||||||
|
|
||||||
getSpy.calls.reset();
|
getSpy.calls.reset();
|
||||||
putSpy.calls.reset();
|
putSpy.calls.reset();
|
||||||
|
delSpy.calls.reset();
|
||||||
|
|
||||||
object.set('foo', 'bar');
|
object.set('foo', 'bar');
|
||||||
await object.save();
|
await object.save();
|
||||||
expect(getSpy.calls.count()).toBe(4);
|
expect(getSpy.calls.count()).toBe(4);
|
||||||
expect(putSpy.calls.count()).toBe(1);
|
expect(putSpy.calls.count()).toBe(2);
|
||||||
|
|
||||||
getSpy.calls.reset();
|
getSpy.calls.reset();
|
||||||
putSpy.calls.reset();
|
putSpy.calls.reset();
|
||||||
@@ -335,7 +371,11 @@ describe_only(() => {
|
|||||||
const query = new Parse.Query(TestObject);
|
const query = new Parse.Query(TestObject);
|
||||||
await query.get(object.id);
|
await query.get(object.id);
|
||||||
expect(getSpy.calls.count()).toBe(3);
|
expect(getSpy.calls.count()).toBe(3);
|
||||||
expect(putSpy.calls.count()).toBe(0);
|
expect(putSpy.calls.count()).toBe(1);
|
||||||
|
expect(delSpy.calls.count()).toBe(2);
|
||||||
|
|
||||||
|
const keys = await cacheAdapter.getAllKeys();
|
||||||
|
expect(keys.length).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('test query', async () => {
|
it('test query', async () => {
|
||||||
@@ -345,11 +385,16 @@ describe_only(() => {
|
|||||||
|
|
||||||
getSpy.calls.reset();
|
getSpy.calls.reset();
|
||||||
putSpy.calls.reset();
|
putSpy.calls.reset();
|
||||||
|
delSpy.calls.reset();
|
||||||
|
|
||||||
const query = new Parse.Query(TestObject);
|
const query = new Parse.Query(TestObject);
|
||||||
await query.get(object.id);
|
await query.get(object.id);
|
||||||
expect(getSpy.calls.count()).toBe(2);
|
expect(getSpy.calls.count()).toBe(2);
|
||||||
expect(putSpy.calls.count()).toBe(0);
|
expect(putSpy.calls.count()).toBe(1);
|
||||||
|
expect(delSpy.calls.count()).toBe(1);
|
||||||
|
|
||||||
|
const keys = await cacheAdapter.getAllKeys();
|
||||||
|
expect(keys.length).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('test query include', async () => {
|
it('test query include', async () => {
|
||||||
@@ -368,7 +413,11 @@ describe_only(() => {
|
|||||||
await query.get(object.id);
|
await query.get(object.id);
|
||||||
|
|
||||||
expect(getSpy.calls.count()).toBe(4);
|
expect(getSpy.calls.count()).toBe(4);
|
||||||
expect(putSpy.calls.count()).toBe(0);
|
expect(putSpy.calls.count()).toBe(1);
|
||||||
|
expect(delSpy.calls.count()).toBe(3);
|
||||||
|
|
||||||
|
const keys = await cacheAdapter.getAllKeys();
|
||||||
|
expect(keys.length).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('query relation without schema', async () => {
|
it('query relation without schema', async () => {
|
||||||
@@ -388,7 +437,11 @@ describe_only(() => {
|
|||||||
expect(objects[0].id).toBe(child.id);
|
expect(objects[0].id).toBe(child.id);
|
||||||
|
|
||||||
expect(getSpy.calls.count()).toBe(2);
|
expect(getSpy.calls.count()).toBe(2);
|
||||||
expect(putSpy.calls.count()).toBe(0);
|
expect(putSpy.calls.count()).toBe(1);
|
||||||
|
expect(delSpy.calls.count()).toBe(3);
|
||||||
|
|
||||||
|
const keys = await cacheAdapter.getAllKeys();
|
||||||
|
expect(keys.length).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('test delete object', async () => {
|
it('test delete object', async () => {
|
||||||
@@ -398,10 +451,15 @@ describe_only(() => {
|
|||||||
|
|
||||||
getSpy.calls.reset();
|
getSpy.calls.reset();
|
||||||
putSpy.calls.reset();
|
putSpy.calls.reset();
|
||||||
|
delSpy.calls.reset();
|
||||||
|
|
||||||
await object.destroy();
|
await object.destroy();
|
||||||
expect(getSpy.calls.count()).toBe(2);
|
expect(getSpy.calls.count()).toBe(2);
|
||||||
expect(putSpy.calls.count()).toBe(0);
|
expect(putSpy.calls.count()).toBe(1);
|
||||||
|
expect(delSpy.calls.count()).toBe(1);
|
||||||
|
|
||||||
|
const keys = await cacheAdapter.getAllKeys();
|
||||||
|
expect(keys.length).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('test schema update class', async () => {
|
it('test schema update class', async () => {
|
||||||
@@ -410,6 +468,7 @@ describe_only(() => {
|
|||||||
|
|
||||||
getSpy.calls.reset();
|
getSpy.calls.reset();
|
||||||
putSpy.calls.reset();
|
putSpy.calls.reset();
|
||||||
|
delSpy.calls.reset();
|
||||||
|
|
||||||
const config = Config.get('test');
|
const config = Config.get('test');
|
||||||
const schema = await config.database.loadSchema();
|
const schema = await config.database.loadSchema();
|
||||||
@@ -452,6 +511,10 @@ describe_only(() => {
|
|||||||
config.database
|
config.database
|
||||||
);
|
);
|
||||||
expect(getSpy.calls.count()).toBe(3);
|
expect(getSpy.calls.count()).toBe(3);
|
||||||
expect(putSpy.calls.count()).toBe(2);
|
expect(putSpy.calls.count()).toBe(3);
|
||||||
|
expect(delSpy.calls.count()).toBe(0);
|
||||||
|
|
||||||
|
const keys = await cacheAdapter.getAllKeys();
|
||||||
|
expect(keys.length).toBe(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -96,6 +96,19 @@ export class RedisCacheAdapter {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Used for testing
|
||||||
|
async getAllKeys() {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.client.keys('*', (err, keys) => {
|
||||||
|
if (err) {
|
||||||
|
reject(err);
|
||||||
|
} else {
|
||||||
|
resolve(keys);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default RedisCacheAdapter;
|
export default RedisCacheAdapter;
|
||||||
|
|||||||
@@ -153,6 +153,7 @@ function makeExpressHandler(appId, promiseHandler) {
|
|||||||
promiseHandler(req)
|
promiseHandler(req)
|
||||||
.then(
|
.then(
|
||||||
result => {
|
result => {
|
||||||
|
clearSchemaCache(req);
|
||||||
if (!result.response && !result.location && !result.text) {
|
if (!result.response && !result.location && !result.text) {
|
||||||
log.error(
|
log.error(
|
||||||
'the handler did not include a "response" or a "location" field'
|
'the handler did not include a "response" or a "location" field'
|
||||||
@@ -186,13 +187,18 @@ function makeExpressHandler(appId, promiseHandler) {
|
|||||||
}
|
}
|
||||||
res.json(result.response);
|
res.json(result.response);
|
||||||
},
|
},
|
||||||
error => next(error)
|
error => {
|
||||||
|
clearSchemaCache(req);
|
||||||
|
next(error);
|
||||||
|
}
|
||||||
)
|
)
|
||||||
.catch(e => {
|
.catch(e => {
|
||||||
|
clearSchemaCache(req);
|
||||||
log.error(`Error generating response. ${inspect(e)}`, { error: e });
|
log.error(`Error generating response. ${inspect(e)}`, { error: e });
|
||||||
next(e);
|
next(e);
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
clearSchemaCache(req);
|
||||||
log.error(`Error handling request: ${inspect(e)}`, { error: e });
|
log.error(`Error handling request: ${inspect(e)}`, { error: e });
|
||||||
next(e);
|
next(e);
|
||||||
}
|
}
|
||||||
@@ -210,3 +216,9 @@ function maskSensitiveUrl(req) {
|
|||||||
}
|
}
|
||||||
return maskUrl;
|
return maskUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function clearSchemaCache(req) {
|
||||||
|
if (req.config && !req.config.enableSingleSchemaCache) {
|
||||||
|
req.config.database.schemaCache.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user