mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-25 03:44:29 +03:00
🐛 Fixed cache invalidation header race conditions
refs https://linear.app/tryghost/issue/ENG-674/ This ensures that all of our dynamic cache invalidation header logic is applied on a per-request basis!
This commit is contained in:
parent
a177600b30
commit
ec697051dc
@ -87,7 +87,7 @@ module.exports = {
|
||||
|
||||
edit: {
|
||||
headers: {
|
||||
cacheInvalidate: false
|
||||
cacheInvalidate: true
|
||||
},
|
||||
options: [
|
||||
'id'
|
||||
@ -111,15 +111,6 @@ module.exports = {
|
||||
});
|
||||
}
|
||||
|
||||
// @NOTE: cache invalidation has to be done manually for now
|
||||
// because the model's wasChanged is not returned from
|
||||
// the service using in-memory repository layer
|
||||
// if (model.wasChanged()) {
|
||||
this.headers.cacheInvalidate = true;
|
||||
// } else {
|
||||
// this.headers.cacheInvalidate = false;
|
||||
// }
|
||||
|
||||
return model;
|
||||
}
|
||||
},
|
||||
|
@ -129,9 +129,7 @@ module.exports = {
|
||||
}
|
||||
|
||||
if (model.wasChanged()) {
|
||||
this.headers.cacheInvalidate = true;
|
||||
} else {
|
||||
this.headers.cacheInvalidate = false;
|
||||
frame.setHeader('X-Cache-Invalidate', '/*');
|
||||
}
|
||||
|
||||
return model;
|
||||
|
@ -122,7 +122,7 @@ module.exports = {
|
||||
return models.Post.add(frame.data.pages[0], frame.options)
|
||||
.then((model) => {
|
||||
if (model.get('status') === 'published') {
|
||||
this.headers.cacheInvalidate = true;
|
||||
frame.setHeader('X-Cache-Invalidate', '/*');
|
||||
}
|
||||
|
||||
return model;
|
||||
@ -166,7 +166,13 @@ module.exports = {
|
||||
async query(frame) {
|
||||
const model = await models.Post.edit(frame.data.pages[0], frame.options);
|
||||
|
||||
this.headers.cacheInvalidate = postsService.handleCacheInvalidation(model);
|
||||
const cacheInvalidation = postsService.handleCacheInvalidation(model);
|
||||
|
||||
if (cacheInvalidation === true) {
|
||||
frame.setHeader('X-Cache-Invalidate', '/*');
|
||||
} else if (cacheInvalidation.value) {
|
||||
frame.setHeader('X-Cache-Invalidate', cacheInvalidation.value);
|
||||
}
|
||||
|
||||
return model;
|
||||
}
|
||||
|
@ -167,10 +167,8 @@ module.exports = {
|
||||
query(frame) {
|
||||
return models.Post.add(frame.data.posts[0], frame.options)
|
||||
.then((model) => {
|
||||
if (model.get('status') !== 'published') {
|
||||
this.headers.cacheInvalidate = false;
|
||||
} else {
|
||||
this.headers.cacheInvalidate = true;
|
||||
if (model.get('status') === 'published') {
|
||||
frame.setHeader('X-Cache-Invalidate', '/*');
|
||||
}
|
||||
|
||||
return model;
|
||||
@ -216,7 +214,12 @@ module.exports = {
|
||||
async query(frame) {
|
||||
let model = await postsService.editPost(frame, {
|
||||
eventHandler: (event, dto) => {
|
||||
this.headers.cacheInvalidate = getCacheHeaderFromEventString(event, dto);
|
||||
const cacheInvalidate = getCacheHeaderFromEventString(event, dto);
|
||||
if (cacheInvalidate === true) {
|
||||
frame.setHeader('X-Cache-Invalidate', '/*');
|
||||
} else if (cacheInvalidate?.value) {
|
||||
frame.setHeader('X-Cache-Invalidate', cacheInvalidate.value);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -40,8 +40,13 @@ module.exports = {
|
||||
};
|
||||
|
||||
const {scheduledResource, preScheduledResource} = await postSchedulingService.publish(resourceType, frame.options.id, frame.data.force, options);
|
||||
const cacheInvalidate = postSchedulingService.handleCacheInvalidation(scheduledResource, preScheduledResource);
|
||||
this.headers.cacheInvalidate = cacheInvalidate;
|
||||
const cacheInvalidation = postSchedulingService.handleCacheInvalidation(scheduledResource, preScheduledResource);
|
||||
|
||||
if (cacheInvalidation === true) {
|
||||
frame.setHeader('X-Cache-Invalidate', '/*');
|
||||
} else if (cacheInvalidation.value) {
|
||||
frame.setHeader('X-Cache-Invalidate', cacheInvalidation.value);
|
||||
}
|
||||
|
||||
const response = {};
|
||||
response[resourceType] = [scheduledResource];
|
||||
|
@ -122,7 +122,7 @@ module.exports = {
|
||||
|
||||
edit: {
|
||||
headers: {
|
||||
cacheInvalidate: true
|
||||
cacheInvalidate: false
|
||||
},
|
||||
permissions: {
|
||||
unsafeAttrsObject(frame) {
|
||||
@ -134,10 +134,8 @@ module.exports = {
|
||||
|
||||
let result = await settingsBREADService.edit(frame.data.settings, frame.options, stripeConnectData);
|
||||
|
||||
if (_.isEmpty(result)) {
|
||||
this.headers.cacheInvalidate = false;
|
||||
} else {
|
||||
this.headers.cacheInvalidate = true;
|
||||
if (!_.isEmpty(result)) {
|
||||
frame.setHeader('X-Cache-Invalidate', '/*');
|
||||
}
|
||||
|
||||
// We need to return all settings here, because we have calculated settings that might change
|
||||
|
@ -124,9 +124,7 @@ module.exports = {
|
||||
}
|
||||
|
||||
if (model.wasChanged()) {
|
||||
this.headers.cacheInvalidate = true;
|
||||
} else {
|
||||
this.headers.cacheInvalidate = false;
|
||||
frame.setHeader('X-Cache-Invalidate', '/*');
|
||||
}
|
||||
|
||||
return model;
|
||||
|
@ -91,7 +91,7 @@ module.exports = {
|
||||
const {theme, themeOverridden} = await themeService.api.installFromGithub(frame.options.ref);
|
||||
|
||||
if (themeOverridden) {
|
||||
this.headers.cacheInvalidate = true;
|
||||
frame.setHeader('X-Cache-Invalidate', '/*');
|
||||
}
|
||||
|
||||
events.emit('theme.uploaded', {name: theme.name});
|
||||
@ -125,8 +125,7 @@ module.exports = {
|
||||
return themeService.api.setFromZip(zip)
|
||||
.then(({theme, themeOverridden}) => {
|
||||
if (themeOverridden) {
|
||||
// CASE: clear cache
|
||||
this.headers.cacheInvalidate = true;
|
||||
frame.setHeader('X-Cache-Invalidate', '/*');
|
||||
}
|
||||
events.emit('theme.uploaded', {name: theme.name});
|
||||
return theme;
|
||||
|
@ -170,7 +170,9 @@ module.exports = {
|
||||
}));
|
||||
}
|
||||
|
||||
this.headers.cacheInvalidate = shouldInvalidateCacheAfterChange(model);
|
||||
if (shouldInvalidateCacheAfterChange(model)) {
|
||||
frame.setHeader('X-Cache-Invalidate', '/*');
|
||||
}
|
||||
|
||||
return model;
|
||||
});
|
||||
|
@ -55,7 +55,7 @@ class PostSchedulingService {
|
||||
*
|
||||
* @param {Object} scheduledResource post or page resource object
|
||||
* @param {Object} preScheduledResource post or page resource object in state before publishing
|
||||
* @returns {Boolean|Object}
|
||||
* @returns {boolean|{value: string}}
|
||||
*/
|
||||
handleCacheInvalidation(scheduledResource, preScheduledResource) {
|
||||
if (
|
||||
|
Loading…
Reference in New Issue
Block a user