There is a few issues with how caches are defined at the moment:
When specifying caches in new Server(...) all values are deep cloned (individual cache settings are also cloned individually as well), this causes issues with any caching strategy that allows passing it data structures that have reference based state (sockets etc.).
See hapijs/catbox-redis#80 (comment)
This is a general problem with hoek.clone itself.
I know there is a discussion on that, we should look into stopping it cloning class instances.
My team, myself and my friends using hapi entirely stopped using options.cache entirely due the issue mentioned above and are only using server.cache.provision with engine being a direct engine instance eg. s.cache.privision({ cache: new CatboxMemory(...) })
Demo time, all of the console.log statements below should print true:
void((async () => {
void(h = require('hapi'));
void(m = require('catbox-memory'));
void(a = new m());
// Scenario 1, config based provision
void(s = new h.Server({ cache: [{ engine: a, name: 'test' }] }));
console.log(s._core.caches.get('test').client.connection === a); // fails due to `m` being deep-cloned
// Scenario 2, active provision
void(await s.cache.provision({ engine: a, name: 'test2' }));
console.log(s._core.caches.get('test2').client.connection === a); // this works
// Scenario 3, active provision but indirect constructor
void(r = require('ioredis'));
void(b = new r())
void(cr = require('./dist/backend/app/server/caches/catbox-redis'));
void(await s.cache.provision({ engine: cr, name: 'redis', client: b }));
console.log(s._core.caches.get('redis').client.connection.client === b); // this doesn't work due to cache options cloning
})());
Result:
The server cache options seem too flexible, often leading to errors in correct usage https://hapijs.com/api#-serveroptionscache as this allows 4 ways to achieve the same thing.
In combination with (1) can lead to entirely unexpected errors when trying to pass through engine constructor options
I propose that we restrict the configuration to the following:
new Server({
cache: [{ // Can still be a single object.
engine: new CatboxMemory({
partition: 'anything', // optional
}), // required
name: 'myOwnCache', // required, maybe use symbol for default cache instead of omitting key to make it more obvious
shared: true // optional
}]
});
The same restriction should apply to server.cache.provision as well, this should be trivial since both, configuration and provision use the same internals.
This would be a breaking in hapi and catbox with very little update time involved.
This shouldn't require any changes to existing catbox engine implementations.
There is a few issues with how caches are defined at the moment:
When specifying caches in
new Server(...)all values are deep cloned (individual cache settings are also cloned individually as well), this causes issues with any caching strategy that allows passing it data structures that have reference based state (sockets etc.).See hapijs/catbox-redis#80 (comment)
This is a general problem with
hoek.cloneitself.I know there is a discussion on that, we should look into stopping it cloning class instances.
My team, myself and my friends using hapi entirely stopped using
options.cacheentirely due the issue mentioned above and are only usingserver.cache.provisionwithenginebeing a direct engine instance eg.s.cache.privision({ cache: new CatboxMemory(...) })Demo time, all of the console.log statements below should print true:
Result:
The server cache options seem too flexible, often leading to errors in correct usage https://hapijs.com/api#-serveroptionscache as this allows 4 ways to achieve the same thing.
In combination with (1) can lead to entirely unexpected errors when trying to pass through engine constructor options
I propose that we restrict the configuration to the following:
The same restriction should apply to
server.cache.provisionas well, this should be trivial since both, configuration andprovisionuse the same internals.This would be a breaking in
hapiandcatboxwith very little update time involved.This shouldn't require any changes to existing catbox engine implementations.