Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Pluggable storage] polishing #568

Open
wants to merge 10 commits into
base: pluggable_storage_baseline
Choose a base branch
from
2 changes: 1 addition & 1 deletion .github/workflows/ci-cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
- name: Set up nodejs
uses: actions/setup-node@v2
with:
node-version: 'lts/*'
node-version: '14'
cache: 'npm'

- name: npm ci
Expand Down
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
},
"dependencies": {
"@babel/runtime": "^7.13.10",
"@splitsoftware/splitio-commons": "1.0.0",
"@splitsoftware/splitio-commons": "1.0.1-rc.2",
"@types/google.analytics": "0.0.40",
"events": "3.1.0",
"ioredis": "^4.28.0",
Expand Down Expand Up @@ -103,15 +103,15 @@
"test-browser-errors": "cross-env NODE_ENV=test karma start karma/errors.ci.karma.conf.js",
"test-browser-gaintegration": "cross-env NODE_ENV=test karma start karma/gaintegration.ci.karma.conf.js",
"test-browser-push": "cross-env NODE_ENV=test karma start karma/push.ci.karma.conf.js",
"test-node": "npm run test-node-unit && npm run test-node-online && npm run test-node-offline && npm run test-node-destroy && npm run test-node-errors && npm run test-node-push && npm run test-node-redis $$ npm run test-node-custom",
"test-node": "npm run test-node-unit && npm run test-node-online && npm run test-node-offline && npm run test-node-destroy && npm run test-node-errors && npm run test-node-push && npm run test-node-consumer-redis $$ npm run test-node-consumer-pluggable",
"test-node-unit": "cross-env NODE_ENV=test tape -r @babel/register \"src/*/**/__tests__/**/!(browser).spec.js\" | tap-min",
"test-node-online": "cross-env NODE_ENV=test tape -r @babel/register src/__tests__/node.spec.js | tap-min",
"test-node-destroy": "cross-env NODE_ENV=test tape -r @babel/register src/__tests__/destroy/node.spec.js | tap-min",
"test-node-errors": "cross-env NODE_ENV=test tape -r @babel/register src/__tests__/errorCatching/node.spec.js | tap-min",
"test-node-offline": "cross-env NODE_ENV=test tape -r @babel/register src/__tests__/offline/node.spec.js | tap-min",
"test-node-push": "cross-env NODE_ENV=test tape -r @babel/register src/__tests__/push/node.spec.js | tap-min",
"test-node-redis": "cross-env NODE_ENV=test tape -r @babel/register \"src/__tests__/consumerMode/node_redis.spec.js\" | tap-min",
"test-node-custom": "cross-env NODE_ENV=test tape -r @babel/register \"src/__tests__/consumerMode/node_custom.spec.js\" | tap-min",
"test-node-consumer-redis": "cross-env NODE_ENV=test tape -r @babel/register \"src/__tests__/consumerMode/node_redis.spec.js\" | tap-min",
"test-node-consumer-pluggable": "cross-env NODE_ENV=test tape -r @babel/register \"src/__tests__/consumerMode/node_pluggable.spec.js\" | tap-min",
"pretest-ts-decls": "npm run build-es && npm run build-cjs && npm link",
"test-ts-decls": "./scripts/ts-tests.sh",
"posttest-ts-decls": "npm unlink && npm install",
Expand Down
10 changes: 5 additions & 5 deletions src/__tests__/browserSuites/ready-promise.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,7 @@ export default function readyPromiseAssertions(fetchMock, assert) {
// We also use the manager to get some of the promises
const manager = splitio.manager();

// promise1 is handled inmediately. Thus, the 'reject' callback is expected to be called in 0.15 seconds aprox.
// promise1 is handled immediately. Thus, the 'reject' callback is expected to be called in 0.15 seconds aprox.
setTimeout(() => {
const promise1 = client.ready();
const tStart = Date.now();
Expand All @@ -434,7 +434,7 @@ export default function readyPromiseAssertions(fetchMock, assert) {
});
}, 0);

// promise2 is handled in 0.15 seconds, when the promise is just rejected. Thus, the 'reject' callback is expected to be called inmediately (0 seconds aprox).
// promise2 is handled in 0.15 seconds, when the promise is just rejected. Thus, the 'reject' callback is expected to be called immediately (0 seconds aprox).
setTimeout(() => {
const promise2 = manager.ready();
const tStart = Date.now();
Expand All @@ -446,11 +446,11 @@ export default function readyPromiseAssertions(fetchMock, assert) {
t.pass('### SDK TIMED OUT - time out is triggered before retry attempt finishes');
assertGetTreatmentControlNotReady(t, client);
const tDelta = Date.now() - tStart;
assert.ok(tDelta < 20, 'The "reject" callback is expected to be called inmediately (0 seconds aprox).');
assert.ok(tDelta < 20, 'The "reject" callback is expected to be called immediately (0 seconds aprox).');
});
}, fromSecondsToMillis(0.15));

// promise3 is handled in 0.2 seconds, when the promise is just resolved. Thus, the 'resolve' callback is expected to be called inmediately (0 seconds aprox).
// promise3 is handled in 0.2 seconds, when the promise is just resolved. Thus, the 'resolve' callback is expected to be called immediately (0 seconds aprox).
setTimeout(() => {
const promise3 = manager.ready();
const tStart = Date.now();
Expand All @@ -459,7 +459,7 @@ export default function readyPromiseAssertions(fetchMock, assert) {
t.pass('### SDK IS READY - retry attempt finishes before the requestTimeoutBeforeReady limit');
assertGetTreatmentWhenReady(t, client);
const tDelta = Date.now() - tStart;
assert.ok(tDelta < 20, 'The "resolve" callback is expected to be called inmediately (0 seconds aprox).');
assert.ok(tDelta < 20, 'The "resolve" callback is expected to be called immediately (0 seconds aprox).');

return Promise.resolve();
}, () => {
Expand Down
31 changes: 15 additions & 16 deletions src/__tests__/consumerMode/ioredisWrapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,21 @@ import { parseRedisOptions } from '../../utils/settings/storage/node';
* Operations fail until `connect` is resolved when the Redis 'ready' event is emitted.
*
* @param {Object} redisOptions redis options with the format expected at `settings.storage.options`
* @returns {import("@splitsoftware/splitio-commons/types/storages/types").ICustomStorageWrapper} wrapper for IORedis client
* @returns {import("@splitsoftware/splitio-commons/types/storages/types").IPluggableStorageWrapper} wrapper for IORedis client
*/
export function ioredisWrapper(redisOptions) {

const options = RedisAdapter._defineOptions(parseRedisOptions(redisOptions));

/** @type ioredis.Redis */
let redis;
const redis = new ioredis(...RedisAdapter._defineLibrarySettings(options));

let isConnected = false;
redis.on('ready', () => { isConnected = true; });
// There is no need to listen for redis 'error' event, because in that case ioredis calls will be rejected.
// It is done to avoid getting the message `Unhandled error event: Error: connect ECONNREFUSED`.
// Also, we cannot reject the connect promise on an error, because the SDK will not get ready if the connection is established after the error.
redis.on('error', () => { });

return {
get(key) {
Expand All @@ -31,9 +40,6 @@ export function ioredisWrapper(redisOptions) {
getKeysByPrefix(prefix) {
return redis.keys(`${prefix}*`);
},
getByPrefix(prefix) {
return this.getKeysByPrefix(prefix).then(keys => redis.mget(...keys));
},
getMany(keys) {
return redis.mget(...keys);
},
Expand Down Expand Up @@ -65,20 +71,13 @@ export function ioredisWrapper(redisOptions) {
return redis.smembers(key);
},
connect() {
const options = RedisAdapter._defineOptions(parseRedisOptions(redisOptions));
redis = new ioredis(...RedisAdapter._defineLibrarySettings(options));

return new Promise((res) => {
redis.on('ready', res);

// There is no need to listen for redis 'error' event, because in that case ioredis calls will be rejected.
// But it is done to avoid getting the ioredis message `Unhandled error event: Error: connect ECONNREFUSED`.
// If we reject the promise, the SDK client will not get ready if the redis connection is established after an error.
redis.on('error', () => { });
if (isConnected) res();
else redis.on('ready', res);
});
},
close() {
return Promise.resolve(redis && redis.disconnect()); // close the connection
disconnect() {
return Promise.resolve(redis && redis.disconnect());
}
};
}
Loading