diff --git a/benchmark/lib/ping/local-resp3-module-with-flags.js b/benchmark/lib/ping/local-resp3-module-with-flags.js index 2af849b938..e58856dcb9 100644 --- a/benchmark/lib/ping/local-resp3-module-with-flags.js +++ b/benchmark/lib/ping/local-resp3-module-with-flags.js @@ -18,7 +18,7 @@ export default async (host) => { return { benchmark() { - return client.withFlags({}).module.ping(); + return client.withTypeMapping({}).module.ping(); }, teardown() { return client.disconnect(); diff --git a/docs/todo.md b/docs/todo.md index ec64adf9d2..4d9c91e2dd 100644 --- a/docs/todo.md +++ b/docs/todo.md @@ -1,3 +1,13 @@ +# Leibale + +- Does `close`/`destory` actually close the connection from the Redis POV? Works with OSS, but what about Redis Enterprie? + +# Docs + +- [v4 to v5](./v4-to-v5.md) - Legacy mode +- [Command Options](./command-options.md) +- [RESP](./RESP.md) + # Missing functionality - `HEXISTS`: accepts one field only, should be the same as `EXISTS` diff --git a/packages/client/lib/client/pool.ts b/packages/client/lib/client/pool.ts index 36c4387a3e..5f1a286cc2 100644 --- a/packages/client/lib/client/pool.ts +++ b/packages/client/lib/client/pool.ts @@ -1,84 +1,242 @@ -import { Pool, Options as PoolOptions, createPool } from 'generic-pool'; -import { RedisFunctions, RedisModules, RedisScripts, RespVersions } from '../RESP/types'; -import RedisClient, { RedisClientType, RedisClientOptions } from '.'; -import { EventEmitter } from 'events'; +// import COMMANDS from '../commands'; +// import { RedisFunctions, RedisModules, RedisScripts, RespVersions, TypeMapping } from '../RESP/types'; +// import RedisClient, { RedisClientType, RedisClientOptions, RedisClientExtensions } from '.'; +// import { EventEmitter } from 'events'; +// import { DoublyLinkedNode, DoublyLinkedList, SinglyLinkedList } from './linked-list'; -type RedisClientPoolOptions< - M extends RedisModules, - F extends RedisFunctions, - S extends RedisScripts, - RESP extends RespVersions -> = RedisClientOptions & PoolOptions; +// export type RedisPoolOptions = typeof RedisClientPool['_DEFAULTS']; -export class RedisClientPool< - M extends RedisModules, - F extends RedisFunctions, - S extends RedisScripts, - RESP extends RespVersions -> extends EventEmitter { - _pool: Pool>; +// export type PoolTask< +// M extends RedisModules, +// F extends RedisFunctions, +// S extends RedisScripts, +// RESP extends RespVersions, +// TYPE_MAPPING extends TypeMapping, +// T = unknown +// > = (client: RedisClientType) => T; - static fromClient< - M extends RedisModules, - F extends RedisFunctions, - S extends RedisScripts, - RESP extends RespVersions - >( - client: RedisClientType, - poolOptions?: PoolOptions - ) { - return new RedisClientPool( - () => client.duplicate(), - poolOptions - ); - } +// export type RedisClientPoolType< +// M extends RedisModules = {}, +// F extends RedisFunctions = {}, +// S extends RedisScripts = {}, +// RESP extends RespVersions = 2, +// TYPE_MAPPING extends TypeMapping = {} +// > = ( +// RedisClientPool & +// RedisClientExtensions +// ); - static fromOptions< - M extends RedisModules, - F extends RedisFunctions, - S extends RedisScripts, - RESP extends RespVersions - >( - options: RedisClientPoolOptions, - poolOptions?: PoolOptions - ) { - return new RedisClientPool( - RedisClient.factory(options), - poolOptions - ); - } +// export class RedisClientPool< +// M extends RedisModules = {}, +// F extends RedisFunctions = {}, +// S extends RedisScripts = {}, +// RESP extends RespVersions = 2, +// TYPE_MAPPING extends TypeMapping = {} +// > extends EventEmitter { +// static fromClient< +// M extends RedisModules, +// F extends RedisFunctions, +// S extends RedisScripts, +// RESP extends RespVersions, +// TYPE_MAPPING extends TypeMapping = {} +// >( +// client: RedisClientType, +// poolOptions: Partial +// ) { +// return RedisClientPool.create( +// () => client.duplicate(), +// poolOptions +// ); +// } - constructor( - clientFactory: () => RedisClientType, - options?: PoolOptions - ) { - super(); +// static fromOptions< +// M extends RedisModules, +// F extends RedisFunctions, +// S extends RedisScripts, +// RESP extends RespVersions, +// TYPE_MAPPING extends TypeMapping = {} +// >( +// options: RedisClientOptions, +// poolOptions: Partial +// ) { +// return RedisClientPool.create( +// RedisClient.factory(options), +// poolOptions +// ); +// } - this._pool = createPool({ - create: async () => { - const client = clientFactory(); +// static create< +// M extends RedisModules, +// F extends RedisFunctions, +// S extends RedisScripts, +// RESP extends RespVersions, +// TYPE_MAPPING extends TypeMapping = {} +// >( +// clientFactory: () => RedisClientType, +// options?: Partial +// ) { +// return new RedisClientPool( +// clientFactory, +// options +// ) as RedisClientPoolType; +// } - // TODO: more events? - client.on('error', (err: Error) => this.emit('error', err)); +// private static _DEFAULTS = { +// /** +// * The minimum number of clients to keep in the pool. +// */ +// minimum: 0, +// /** +// * The maximum number of clients to keep in the pool. +// */ +// maximum: 1, +// /** +// * The maximum time a task can wait for a client to become available. +// */ +// acquireTimeout: 3000, +// /** +// * When there are `> minimum && < maximum` clients in the pool, the pool will wait for `cleanupDelay` milliseconds before closing the extra clients. +// */ +// cleanupDelay: 3000 +// }; - await client.connect(); +// private readonly _clientFactory: () => RedisClientType; +// private readonly _options: Required; +// private readonly _idleClients = new SinglyLinkedList>(); +// private readonly _usedClients = new DoublyLinkedList>(); +// private readonly _tasksQueue = new SinglyLinkedList<{ +// resolve: (value: T | PromiseLike) => void; +// reject: (reason?: unknown) => void; +// fn: PoolTask; +// }>(); - return client; - }, - // TODO: destroy has to return a Promise?! - destroy: async client => client.disconnect() - }, options); - } +// constructor( +// clientFactory: () => RedisClientType, +// options?: Partial +// ) { +// super(); - execute(fn: () => T): Promise { - return this._pool.use(fn); - } +// this._clientFactory = clientFactory; +// this._options = { +// ...RedisClientPool._DEFAULTS, +// ...options +// }; +// this._initate(); +// } - close() { - // TODO - } +// private async _initate() { +// const promises = []; +// while (promises.length < this._options.minimum) { +// promises.push(this._create()); +// } - disconnect() { - // TODO - } -} +// try { +// await Promise.all(promises); +// } catch (err) { +// this.destroy(); +// this.emit('error', err); +// } +// } + +// private async _create() { +// const client = this._clientFactory() +// // TODO: more events? +// .on('error', (err: Error) => this.emit('error', err)); + +// const node = this._usedClients.push(client); + +// await client.connect(); + +// this._usedClients.remove(node); + +// return client; +// } + +// execute(fn: PoolTask): Promise { +// return new Promise((resolve, reject) => { +// let client = this._idleClients.shift(); +// if (!client) { +// this._tasksQueue.push({ +// // @ts-ignore +// resolve, +// reject, +// fn +// }); + +// if (this._idleClients.length + this._usedClients.length < this._options.maximum) { +// this._create(); +// } + +// return; +// } + +// const node = this._usedClients.push(client); +// // @ts-ignore +// this._executeTask(node, resolve, reject, fn); +// }); +// } + +// private _executeTask( +// node: DoublyLinkedNode>, +// resolve: (value: T | PromiseLike) => void, +// reject: (reason?: unknown) => void, +// fn: PoolTask +// ) { +// const result = fn(node.value); +// if (result instanceof Promise) { +// result.then(resolve, reject); +// result.finally(() => this._returnClient(node)) +// } else { +// resolve(result); +// this._returnClient(node); +// } +// } + +// private _returnClient(node: DoublyLinkedListNode>) { +// const task = this._tasksQueue.shift(); +// if (task) { +// this._executeTask(node, task.resolve, task.reject, task.fn); +// return; +// } + +// if (this._idleClients.length >= this._options.minimum) { +// node.client.destroy(); +// return; +// } + +// this._usedClients.remove(node); +// this._idleClients.push(node.client); +// } + +// async close() { +// const promises = []; + +// for (const client of this._idleClients) { +// promises.push(client.close()); +// } + +// this._idleClients.reset(); + +// for (const client of this._usedClients) { +// promises.push(client.close()); +// } + +// this._usedClients.reset(); + +// await Promise.all(promises); +// } + +// destroy() { +// for (const client of this._idleClients) { +// client.destroy(); +// } + +// this._idleClients.reset(); + +// for (const client of this._usedClients) { +// client.destroy(); +// } + +// this._usedClients.reset(); +// } +// } diff --git a/test.mjs b/test.mjs new file mode 100644 index 0000000000..6aa12b67e5 --- /dev/null +++ b/test.mjs @@ -0,0 +1,260 @@ +// // // import { createClient } from './benchmark/node_modules/@redis/client/dist/index.js'; +// // // import Redis from './benchmark/node_modules/ioredis/built/index.js'; +// // // import { setTimeout } from 'node:timers/promises'; + +// // // const client = createClient(); +// // // client.on('error', err => console.error(err)); + +// // // await client.connect(); + +// // // const io = new Redis({ +// // // lazyConnect: true, +// // // enableAutoPipelining: true +// // // }); +// // // await io.connect(); + +// // // const TIMES = 1_000; + +// // // while (true) { +// // // await benchmark('redis', () => { +// // // const promises = []; +// // // for (let i = 0; i < TIMES; i++) { +// // // promises.push(client.ping()); +// // // } + +// // // return Promise.all(promises); +// // // }); + +// // // await benchmark('ioredis', () => { +// // // const promises = []; +// // // for (let i = 0; i < TIMES; i++) { +// // // promises.push(io.ping()); +// // // } + +// // // return Promise.all(promises); +// // // }); +// // // } + +// // // async function benchmark(name, fn) { +// // // const start = process.hrtime.bigint(); + +// // // await fn(); + +// // // const took = Number(process.hrtime.bigint() - start); +// // // console.log(took, name); + +// // // console.log('Sleep'); +// // // await setTimeout(1000); +// // // console.log('Continue'); +// // // } + + // import Redis from 'ioredis'; + + // const cluster = new Redis.Cluster([{ + // port: 6379, + // host: "127.0.0.1", + // }]); + + // setInterval(() => { + // let i = 0; + // cluster.on('node-', () => { + // if (++3) { + // cluster.refreshSlotsCache(err => { + // console.log('done', err); + // }); + // i = 0; + // } + // }) + + // }, 5000); + +// import { createCluster } from './packages/client/dist/index.js'; +// import { setTimeout } from 'node:timers/promises'; + +// const cluster = createCluster({ +// rootNodes: [{}] +// }); + +// cluster.on('error', err => console.error(err)); + +// await cluster.connect(); + +// console.log( +// await Promise.all([ +// cluster.ping(), +// cluster.ping(), +// cluster.set('1', '1'), +// cluster.get('1'), +// cluster.get('2'), +// cluster.multi().ping().ping().get('a').set('a', 'b').get('a').execTyped() +// // cluster +// ]) +// ); + +// import { createClient } from './packages/client/dist/index.js'; + +// const client = createClient(); + +// client.a(); + +// client.on('error', err => console.error('Redis Client Error', err)); + +// await client.connect(); + +// const legacy = client.legacy(); + +// console.log( +// await client.multi() +// .ping() +// .ping() +// .aaa() +// .exec(), +// await client.multi() +// .ping() +// .ping() +// .execTyped() +// ); + +// legacy.multi() +// .ping() +// .ping() +// .sendCommand(['PING', 'LEIBALE']) +// .exec((err, replies) => { +// console.log(err, replies); +// client.destroy(); +// }) + +// for (let i = 0; i < 100; i++) { +// const promises = []; +// for (let j = 0; j < 5; j++) { +// promises.push(client.sendCommand(['PING'])); +// } + +// console.log( +// await Promise.all(promises) +// ); +// } + +// // // const I = 100, +// // // J = 1_000; + +// // // for (let i = 0; i < I; i++) { +// // // const promises = new Array(J); +// // // for (let j = 0; j < J; j++) { +// // // promises[j] = client.ping(); +// // // } + +// // // await Promise.all(promises); +// // // } + +// import { writeFile } from 'node:fs/promises'; + +// function gen() { + +// const lines = [ +// `// ${new Date().toJSON()}`, +// 'import * as B from "./b";', +// 'export default {' +// ]; + +// for (let i = 0; i < 40000; i++) { +// lines.push(` ${i}: B,`); +// } + +// lines.push('} as const;'); + +// return lines.join('\n'); +// } + +// await writeFile('./a.ts', gen()); + +// import { createClient } from '@redis/client'; + +// console.log(new Date().toJSON()); + +// const client = createClient({ +// url: 'redis://default:VugDBHGYAectnTj25wmCCAuhPOu3xkhk@redis-11344.c240.us-east-1-3.ec2.cloud.redislabs.com:11344' +// }); + +// client.on('error', err => console.error('11111', err, new Date().toJSON())); + +// await client.connect(); + +// const client2 = createClient({ +// url: 'redis://default:VugDBHGYAectnTj25wmCCAuhPOu3xkhk@redis-11344.c240.us-east-1-3.ec2.cloud.redislabs.com:11344', +// pingInterval: 60000 +// }); + +// client2.on('error', err => console.error('22222', err, new Date().toJSON())); + +// await client2.connect(); + +import { createClient, RESP_TYPES } from '@redis/client'; + +const client = createClient({ + RESP: 3, + name: 'test', + commandOptions: { + asap: true, + typeMapping: { + [RESP_TYPES.BLOB_STRING]: Buffer + } + } +}); + +client.on('error', err => console.error(err)); + +await client.connect(); + + +const controller = new AbortController(); + +try { + const promise = client.withAbortSignal(controller.signal).set('key', 'value'); + controller.abort(); + console.log('!!', await promise); +} catch (err) { + // AbortError +} + +await Promise.all([ + client.ping('a'), + client.ping('b') +]) + +const asap = client.asap(); + +await Promise.all([ + asap.ping('aa'), + asap.ping('bb') +]) + +await client.set('another', 'value'); + +for await (const keys of client.scanIterator()) { + console.log(keys); +} + +// console.log( +// await Promise.all([ +// client.get('key'), +// client.asap().get('a'), +// client.withTypeMapping({}).get('key') +// ]) +// ); + +// await client.set('key', 'value'); + +// const controller = new AbortController(); + +// controller.abort(); + +// client.withAbortSignal(controller.signal).get('key') +// .then(a => console.log(a)) +// .catch(err => { +// console.error(err); +// }); + +// controller.abort(); + +// client.destroy(); diff --git a/test/package-lock.json b/test/package-lock.json new file mode 100644 index 0000000000..2419e2490c --- /dev/null +++ b/test/package-lock.json @@ -0,0 +1,232 @@ +{ + "name": "test", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "test", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "@redis/client": "^1.5.7", + "ioredis": "^5.3.2", + "local": "file:../packages/client", + "redis": "^4.6.6", + "redis-om": "^0.3.6" + } + }, + "node_modules/@ioredis/commands": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.2.0.tgz", + "integrity": "sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==" + }, + "node_modules/@redis/bloom": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.2.0.tgz", + "integrity": "sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==", + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/@redis/client": { + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.5.7.tgz", + "integrity": "sha512-gaOBOuJPjK5fGtxSseaKgSvjiZXQCdLlGg9WYQst+/GRUjmXaiB5kVkeQMRtPc7Q2t93XZcJfBMSwzs/XS9UZw==", + "dependencies": { + "cluster-key-slot": "1.1.2", + "generic-pool": "3.9.0", + "yallist": "4.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@redis/graph": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.1.0.tgz", + "integrity": "sha512-16yZWngxyXPd+MJxeSr0dqh2AIOi8j9yXKcKCwVaKDbH3HTuETpDVPcLujhFYVPtYrngSco31BUcSa9TH31Gqg==", + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/@redis/json": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.4.tgz", + "integrity": "sha512-LUZE2Gdrhg0Rx7AN+cZkb1e6HjoSKaeeW8rYnt89Tly13GBI5eP4CwDVr+MY8BAYfCg4/N15OUrtLoona9uSgw==", + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/@redis/search": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@redis/search/-/search-1.1.2.tgz", + "integrity": "sha512-/cMfstG/fOh/SsE+4/BQGeuH/JJloeWuH+qJzM8dbxuWvdWibWAOAHHCZTMPhV3xIlH4/cUEIA8OV5QnYpaVoA==", + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/@redis/time-series": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.0.4.tgz", + "integrity": "sha512-ThUIgo2U/g7cCuZavucQTQzA9g9JbDDY2f64u3AbAoz/8vE2lt2U37LamDUVChhaDA3IRT9R6VvJwqnUfTJzng==", + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/cluster-key-slot": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", + "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/denque": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", + "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/generic-pool": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz", + "integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/ioredis": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.3.2.tgz", + "integrity": "sha512-1DKMMzlIHM02eBBVOFQ1+AolGjs6+xEcM4PDL7NqOS6szq7H9jSaEkIUH6/a5Hl241LzW6JLSiAbNvTQjUupUA==", + "dependencies": { + "@ioredis/commands": "^1.1.1", + "cluster-key-slot": "^1.1.0", + "debug": "^4.3.4", + "denque": "^2.1.0", + "lodash.defaults": "^4.2.0", + "lodash.isarguments": "^3.1.0", + "redis-errors": "^1.2.0", + "redis-parser": "^3.0.0", + "standard-as-callback": "^2.1.0" + }, + "engines": { + "node": ">=12.22.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/ioredis" + } + }, + "node_modules/local": { + "name": "@redis/client", + "version": "2.0.0-next.1", + "resolved": "file:../packages/client", + "license": "MIT", + "dependencies": { + "cluster-key-slot": "1.1.2", + "generic-pool": "3.9.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==" + }, + "node_modules/lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==" + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/redis": { + "version": "4.6.6", + "resolved": "https://registry.npmjs.org/redis/-/redis-4.6.6.tgz", + "integrity": "sha512-aLs2fuBFV/VJ28oLBqYykfnhGGkFxvx0HdCEBYdJ99FFbSEMZ7c1nVKwR6ZRv+7bb7JnC0mmCzaqu8frgOYhpA==", + "dependencies": { + "@redis/bloom": "1.2.0", + "@redis/client": "1.5.7", + "@redis/graph": "1.1.0", + "@redis/json": "1.0.4", + "@redis/search": "1.1.2", + "@redis/time-series": "1.0.4" + } + }, + "node_modules/redis-errors": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", + "integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==", + "engines": { + "node": ">=4" + } + }, + "node_modules/redis-om": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/redis-om/-/redis-om-0.3.6.tgz", + "integrity": "sha512-WRmrAm1n1EQIQbEwbfqpceuxHgr7LKOZ471c/KGxyOTVFFm53E0S7vFSZA7a1Jnga7aHTOYqLhhMWE0lKKdsNw==", + "dependencies": { + "redis": "^4.0.4", + "ulid": "^2.3.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/redis-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", + "integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==", + "dependencies": { + "redis-errors": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/standard-as-callback": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz", + "integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==" + }, + "node_modules/ulid": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/ulid/-/ulid-2.3.0.tgz", + "integrity": "sha512-keqHubrlpvT6G2wH0OEfSW4mquYRcbe/J8NMmveoQOjUqmo+hXtO+ORCpWhdbZ7k72UtY61BL7haGxW6enBnjw==", + "bin": { + "ulid": "bin/cli.js" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } +} diff --git a/test/package.json b/test/package.json new file mode 100644 index 0000000000..f7fbbbf5d1 --- /dev/null +++ b/test/package.json @@ -0,0 +1,19 @@ +{ + "name": "test", + "version": "1.0.0", + "description": "", + "main": "index.js", + "type": "module", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "dependencies": { + "@redis/client": "^1.5.7", + "ioredis": "^5.3.2", + "local": "file:../packages/client", + "redis": "^4.6.6", + "redis-om": "^0.3.6" + } +} diff --git a/test/test.js b/test/test.js new file mode 100644 index 0000000000..8d9b54bc27 --- /dev/null +++ b/test/test.js @@ -0,0 +1,26 @@ +import { createClient } from '@redis/client'; +import { setTimeout } from 'node:timers/promises'; + +const client = createClient(); +client.on('error', err => console.error(err)); + +await client.connect(); + +await client.set('key', 'a'.repeat(1_000)); + +throw 'a'; + +while (true) { + const promises = []; + for (let i = 0; i < 20_000; i++) { + promises.push(client.sendCommand(['HMSET', `aa${i.toString()}`, 'txt1', Math.random().toString()])); + } + + await Promise.all(promises); + console.log( + await client.dbSize(), + (await client.info('MEMORY')).split('\n')[1] + ); + + await setTimeout(1000); +}