Added adapter caching based on features

refs https://github.com/TryGhost/Toolbox/issues/384

- Adapter cache was not able to store multiple object instances derived from same Base class. This created a need to create boilerplate "shell" classes inheriting from the Base class, e.g.: ImageSizeCacheSyncInMemory etc.
- Having feature-based adapter instance caching in the adapter manager allows to simplify configuration and reuse the "base class" instead of creating artificial "shell" classes.
- For example with this change both image sizes and settings caches will create separate cache instances deriving from default "Memory" class. Less code, less configuration!
This commit is contained in:
Naz 2022-09-06 12:35:07 +08:00
parent 0f86a05ed4
commit 37dd187fe6
No known key found for this signature in database
6 changed files with 53 additions and 23 deletions

View File

@ -84,8 +84,10 @@ module.exports = class AdapterManager {
});
}
if (adapterCache[adapterName]) {
return adapterCache[adapterName];
// @NOTE: example cache key value 'email:newsletters:custom-newsletter-adapter'
const adapterCacheKey = `${adapterName}:${adapterClassName}`;
if (adapterCache[adapterCacheKey]) {
return adapterCache[adapterCacheKey];
}
/** @type AdapterConstructor */
@ -143,7 +145,7 @@ module.exports = class AdapterManager {
}
}
adapterCache[adapterName] = adapter;
adapterCache[adapterCacheKey] = adapter;
return adapter;
}

View File

@ -129,4 +129,48 @@ describe('AdapterManager', function () {
should.fail(err, null, 'Should not have errored');
}
});
it('Creates separate class instances for adapters requested for different features', function () {
const pathsToAdapters = [
'/path'
];
const loadAdapterFromPath = sinon.stub();
loadAdapterFromPath.withArgs('/path/mail/custom')
.returns(CustomMailAdapter);
loadAdapterFromPath.withArgs('/path/mail/default')
.returns(DefaultMailAdapter);
const adapterManager = new AdapterManager({
loadAdapterFromPath,
pathsToAdapters
});
adapterManager.registerAdapter('mail', BaseMailAdapter);
let mailNewslettersAdapter;
try {
mailNewslettersAdapter = adapterManager.getAdapter('mail:newsletters', 'custom');
should.ok(mailNewslettersAdapter instanceof BaseMailAdapter);
should.ok(mailNewslettersAdapter instanceof CustomMailAdapter);
} catch (err) {
should.fail(err, null, 'Should not have errored');
}
let mailNotificationsAdapter;
try {
mailNotificationsAdapter = adapterManager.getAdapter('mail:notifications', 'custom');
should.ok(mailNotificationsAdapter instanceof BaseMailAdapter);
should.ok(mailNotificationsAdapter instanceof CustomMailAdapter);
} catch (err) {
should.fail(err, null, 'Should not have errored');
}
should.notEqual(mailNewslettersAdapter, mailNotificationsAdapter);
const secondMailNewslettersAdapter = adapterManager.getAdapter('mail:newsletters', 'custom');
should.equal(mailNewslettersAdapter, secondMailNewslettersAdapter);
});
});

View File

@ -1,7 +0,0 @@
const Memory = require('./Memory');
class ImageSizesCacheSyncInMemory extends Memory {
}
module.exports = ImageSizesCacheSyncInMemory;

View File

@ -1,7 +0,0 @@
const Memory = require('./Memory');
class SettingsCacheSyncInMemory extends Memory {
}
module.exports = SettingsCacheSyncInMemory;

View File

@ -26,8 +26,8 @@ module.exports = {
getAdapter(name) {
const adapterServiceConfig = getAdapterServiceConfig(config);
const {adapterType, adapterName, adapterConfig} = resolveAdapterOptions(name, adapterServiceConfig);
const {adapterName, adapterConfig} = resolveAdapterOptions(name, adapterServiceConfig);
return adapterManager.getAdapter(adapterType, adapterName, adapterConfig);
return adapterManager.getAdapter(name, adapterName, adapterConfig);
}
};

View File

@ -26,10 +26,8 @@
},
"cache": {
"active": "Memory",
"settings": "SettingsCacheSyncInMemory",
"SettingsCacheSyncInMemory": {},
"imageSizes": "ImageSizesCacheSyncInMemory",
"ImageSizesCacheSyncInMemory": {}
"settings": {},
"imageSizes": {}
}
},
"storage": {