Skip to content

Commit edfa1df

Browse files
authored
Cleanup Schema cache per request (parse-community#6126)
* remove enableSingleSchemaCache from test * clear schema cache per request
1 parent f26008f commit edfa1df

File tree

4 files changed

+112
-21
lines changed

4 files changed

+112
-21
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,6 @@ lib/
5656

5757
# Folder created by FileSystemAdapter
5858
/files
59+
60+
# Redis Dump
61+
dump.rdb

spec/RedisCacheAdapter.spec.js

+83-20
Original file line numberDiff line numberDiff line change
@@ -172,24 +172,30 @@ describe_only(() => {
172172
let cacheAdapter;
173173
let getSpy;
174174
let putSpy;
175+
let delSpy;
175176

176177
beforeEach(async () => {
177178
cacheAdapter = new RedisCacheAdapter();
178-
await cacheAdapter.clear();
179179
await reconfigureServer({
180180
cacheAdapter,
181-
enableSingleSchemaCache: true,
182181
});
182+
await cacheAdapter.clear();
183+
183184
getSpy = spyOn(cacheAdapter, 'get').and.callThrough();
184185
putSpy = spyOn(cacheAdapter, 'put').and.callThrough();
186+
delSpy = spyOn(cacheAdapter, 'del').and.callThrough();
185187
});
186188

187189
it('test new object', async () => {
188190
const object = new TestObject();
189191
object.set('foo', 'bar');
190192
await object.save();
191193
expect(getSpy.calls.count()).toBe(3);
192-
expect(putSpy.calls.count()).toBe(2);
194+
expect(putSpy.calls.count()).toBe(3);
195+
expect(delSpy.calls.count()).toBe(1);
196+
197+
const keys = await cacheAdapter.getAllKeys();
198+
expect(keys.length).toBe(0);
193199
});
194200

195201
it('test new object multiple fields', async () => {
@@ -202,7 +208,11 @@ describe_only(() => {
202208
});
203209
await container.save();
204210
expect(getSpy.calls.count()).toBe(3);
205-
expect(putSpy.calls.count()).toBe(2);
211+
expect(putSpy.calls.count()).toBe(3);
212+
expect(delSpy.calls.count()).toBe(1);
213+
214+
const keys = await cacheAdapter.getAllKeys();
215+
expect(keys.length).toBe(0);
206216
});
207217

208218
it('test update existing fields', async () => {
@@ -216,7 +226,11 @@ describe_only(() => {
216226
object.set('foo', 'barz');
217227
await object.save();
218228
expect(getSpy.calls.count()).toBe(3);
219-
expect(putSpy.calls.count()).toBe(0);
229+
expect(putSpy.calls.count()).toBe(1);
230+
expect(delSpy.calls.count()).toBe(2);
231+
232+
const keys = await cacheAdapter.getAllKeys();
233+
expect(keys.length).toBe(0);
220234
});
221235

222236
it('test saveAll / destroyAll', async () => {
@@ -234,14 +248,18 @@ describe_only(() => {
234248
}
235249
await Parse.Object.saveAll(objects);
236250
expect(getSpy.calls.count()).toBe(21);
237-
expect(putSpy.calls.count()).toBe(10);
251+
expect(putSpy.calls.count()).toBe(11);
238252

239253
getSpy.calls.reset();
240254
putSpy.calls.reset();
241255

242256
await Parse.Object.destroyAll(objects);
243257
expect(getSpy.calls.count()).toBe(11);
244-
expect(putSpy.calls.count()).toBe(0);
258+
expect(putSpy.calls.count()).toBe(1);
259+
expect(delSpy.calls.count()).toBe(3);
260+
261+
const keys = await cacheAdapter.getAllKeys();
262+
expect(keys.length).toBe(0);
245263
});
246264

247265
it('test saveAll / destroyAll batch', async () => {
@@ -259,14 +277,18 @@ describe_only(() => {
259277
}
260278
await Parse.Object.saveAll(objects, { batchSize: 5 });
261279
expect(getSpy.calls.count()).toBe(22);
262-
expect(putSpy.calls.count()).toBe(5);
280+
expect(putSpy.calls.count()).toBe(7);
263281

264282
getSpy.calls.reset();
265283
putSpy.calls.reset();
266284

267285
await Parse.Object.destroyAll(objects, { batchSize: 5 });
268286
expect(getSpy.calls.count()).toBe(12);
269-
expect(putSpy.calls.count()).toBe(0);
287+
expect(putSpy.calls.count()).toBe(2);
288+
expect(delSpy.calls.count()).toBe(5);
289+
290+
const keys = await cacheAdapter.getAllKeys();
291+
expect(keys.length).toBe(0);
270292
});
271293

272294
it('test add new field to existing object', async () => {
@@ -280,7 +302,11 @@ describe_only(() => {
280302
object.set('new', 'barz');
281303
await object.save();
282304
expect(getSpy.calls.count()).toBe(3);
283-
expect(putSpy.calls.count()).toBe(1);
305+
expect(putSpy.calls.count()).toBe(2);
306+
expect(delSpy.calls.count()).toBe(2);
307+
308+
const keys = await cacheAdapter.getAllKeys();
309+
expect(keys.length).toBe(0);
284310
});
285311

286312
it('test add multiple fields to existing object', async () => {
@@ -300,7 +326,11 @@ describe_only(() => {
300326
});
301327
await object.save();
302328
expect(getSpy.calls.count()).toBe(3);
303-
expect(putSpy.calls.count()).toBe(1);
329+
expect(putSpy.calls.count()).toBe(2);
330+
expect(delSpy.calls.count()).toBe(2);
331+
332+
const keys = await cacheAdapter.getAllKeys();
333+
expect(keys.length).toBe(0);
304334
});
305335

306336
it('test user', async () => {
@@ -310,32 +340,42 @@ describe_only(() => {
310340
await user.signUp();
311341

312342
expect(getSpy.calls.count()).toBe(8);
313-
expect(putSpy.calls.count()).toBe(1);
343+
expect(putSpy.calls.count()).toBe(2);
344+
expect(delSpy.calls.count()).toBe(1);
345+
346+
const keys = await cacheAdapter.getAllKeys();
347+
expect(keys.length).toBe(0);
314348
});
315349

316350
it('test allowClientCreation false', async () => {
317351
const object = new TestObject();
318352
await object.save();
319353
await reconfigureServer({
320354
cacheAdapter,
321-
enableSingleSchemaCache: true,
322355
allowClientClassCreation: false,
323356
});
357+
await cacheAdapter.clear();
358+
324359
getSpy.calls.reset();
325360
putSpy.calls.reset();
361+
delSpy.calls.reset();
326362

327363
object.set('foo', 'bar');
328364
await object.save();
329365
expect(getSpy.calls.count()).toBe(4);
330-
expect(putSpy.calls.count()).toBe(1);
366+
expect(putSpy.calls.count()).toBe(2);
331367

332368
getSpy.calls.reset();
333369
putSpy.calls.reset();
334370

335371
const query = new Parse.Query(TestObject);
336372
await query.get(object.id);
337373
expect(getSpy.calls.count()).toBe(3);
338-
expect(putSpy.calls.count()).toBe(0);
374+
expect(putSpy.calls.count()).toBe(1);
375+
expect(delSpy.calls.count()).toBe(2);
376+
377+
const keys = await cacheAdapter.getAllKeys();
378+
expect(keys.length).toBe(0);
339379
});
340380

341381
it('test query', async () => {
@@ -345,11 +385,16 @@ describe_only(() => {
345385

346386
getSpy.calls.reset();
347387
putSpy.calls.reset();
388+
delSpy.calls.reset();
348389

349390
const query = new Parse.Query(TestObject);
350391
await query.get(object.id);
351392
expect(getSpy.calls.count()).toBe(2);
352-
expect(putSpy.calls.count()).toBe(0);
393+
expect(putSpy.calls.count()).toBe(1);
394+
expect(delSpy.calls.count()).toBe(1);
395+
396+
const keys = await cacheAdapter.getAllKeys();
397+
expect(keys.length).toBe(0);
353398
});
354399

355400
it('test query include', async () => {
@@ -368,7 +413,11 @@ describe_only(() => {
368413
await query.get(object.id);
369414

370415
expect(getSpy.calls.count()).toBe(4);
371-
expect(putSpy.calls.count()).toBe(0);
416+
expect(putSpy.calls.count()).toBe(1);
417+
expect(delSpy.calls.count()).toBe(3);
418+
419+
const keys = await cacheAdapter.getAllKeys();
420+
expect(keys.length).toBe(0);
372421
});
373422

374423
it('query relation without schema', async () => {
@@ -388,7 +437,11 @@ describe_only(() => {
388437
expect(objects[0].id).toBe(child.id);
389438

390439
expect(getSpy.calls.count()).toBe(2);
391-
expect(putSpy.calls.count()).toBe(0);
440+
expect(putSpy.calls.count()).toBe(1);
441+
expect(delSpy.calls.count()).toBe(3);
442+
443+
const keys = await cacheAdapter.getAllKeys();
444+
expect(keys.length).toBe(0);
392445
});
393446

394447
it('test delete object', async () => {
@@ -398,10 +451,15 @@ describe_only(() => {
398451

399452
getSpy.calls.reset();
400453
putSpy.calls.reset();
454+
delSpy.calls.reset();
401455

402456
await object.destroy();
403457
expect(getSpy.calls.count()).toBe(2);
404-
expect(putSpy.calls.count()).toBe(0);
458+
expect(putSpy.calls.count()).toBe(1);
459+
expect(delSpy.calls.count()).toBe(1);
460+
461+
const keys = await cacheAdapter.getAllKeys();
462+
expect(keys.length).toBe(0);
405463
});
406464

407465
it('test schema update class', async () => {
@@ -410,6 +468,7 @@ describe_only(() => {
410468

411469
getSpy.calls.reset();
412470
putSpy.calls.reset();
471+
delSpy.calls.reset();
413472

414473
const config = Config.get('test');
415474
const schema = await config.database.loadSchema();
@@ -452,6 +511,10 @@ describe_only(() => {
452511
config.database
453512
);
454513
expect(getSpy.calls.count()).toBe(3);
455-
expect(putSpy.calls.count()).toBe(2);
514+
expect(putSpy.calls.count()).toBe(3);
515+
expect(delSpy.calls.count()).toBe(0);
516+
517+
const keys = await cacheAdapter.getAllKeys();
518+
expect(keys.length).toBe(1);
456519
});
457520
});

src/Adapters/Cache/RedisCacheAdapter/index.js

+13
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,19 @@ export class RedisCacheAdapter {
9696
})
9797
);
9898
}
99+
100+
// Used for testing
101+
async getAllKeys() {
102+
return new Promise((resolve, reject) => {
103+
this.client.keys('*', (err, keys) => {
104+
if (err) {
105+
reject(err);
106+
} else {
107+
resolve(keys);
108+
}
109+
});
110+
});
111+
}
99112
}
100113

101114
export default RedisCacheAdapter;

src/PromiseRouter.js

+13-1
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ function makeExpressHandler(appId, promiseHandler) {
153153
promiseHandler(req)
154154
.then(
155155
result => {
156+
clearSchemaCache(req);
156157
if (!result.response && !result.location && !result.text) {
157158
log.error(
158159
'the handler did not include a "response" or a "location" field'
@@ -186,13 +187,18 @@ function makeExpressHandler(appId, promiseHandler) {
186187
}
187188
res.json(result.response);
188189
},
189-
error => next(error)
190+
error => {
191+
clearSchemaCache(req);
192+
next(error);
193+
}
190194
)
191195
.catch(e => {
196+
clearSchemaCache(req);
192197
log.error(`Error generating response. ${inspect(e)}`, { error: e });
193198
next(e);
194199
});
195200
} catch (e) {
201+
clearSchemaCache(req);
196202
log.error(`Error handling request: ${inspect(e)}`, { error: e });
197203
next(e);
198204
}
@@ -210,3 +216,9 @@ function maskSensitiveUrl(req) {
210216
}
211217
return maskUrl;
212218
}
219+
220+
function clearSchemaCache(req) {
221+
if (req.config && !req.config.enableSingleSchemaCache) {
222+
req.config.database.schemaCache.clear();
223+
}
224+
}

0 commit comments

Comments
 (0)