1
0
mirror of https://github.com/redis/node-redis.git synced 2025-08-07 13:22:56 +03:00

Merge branch 'v5' of github.com:leibale/node-redis into v5

This commit is contained in:
Leibale
2023-06-22 18:33:45 -04:00
7 changed files with 778 additions and 73 deletions

View File

@@ -18,7 +18,7 @@ export default async (host) => {
return {
benchmark() {
return client.withFlags({}).module.ping();
return client.withTypeMapping({}).module.ping();
},
teardown() {
return client.disconnect();

View File

@@ -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`

View File

@@ -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<M, F, S, RESP> & 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<RedisClientType<M, F, S, RESP>>;
// export type PoolTask<
// M extends RedisModules,
// F extends RedisFunctions,
// S extends RedisScripts,
// RESP extends RespVersions,
// TYPE_MAPPING extends TypeMapping,
// T = unknown
// > = (client: RedisClientType<M, F, S, RESP, TYPE_MAPPING>) => T;
static fromClient<
M extends RedisModules,
F extends RedisFunctions,
S extends RedisScripts,
RESP extends RespVersions
>(
client: RedisClientType<M, F, S, RESP>,
poolOptions?: PoolOptions
) {
return new RedisClientPool<M, F, S, RESP>(
() => client.duplicate(),
poolOptions
);
}
// export type RedisClientPoolType<
// M extends RedisModules = {},
// F extends RedisFunctions = {},
// S extends RedisScripts = {},
// RESP extends RespVersions = 2,
// TYPE_MAPPING extends TypeMapping = {}
// > = (
// RedisClientPool<M, F, S, RESP, TYPE_MAPPING> &
// RedisClientExtensions<M, F, S, RESP, TYPE_MAPPING>
// );
static fromOptions<
M extends RedisModules,
F extends RedisFunctions,
S extends RedisScripts,
RESP extends RespVersions
>(
options: RedisClientPoolOptions<M, F, S, RESP>,
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<M, F, S, RESP, TYPE_MAPPING>,
// poolOptions: Partial<RedisPoolOptions>
// ) {
// return RedisClientPool.create(
// () => client.duplicate(),
// poolOptions
// );
// }
constructor(
clientFactory: () => RedisClientType<M, F, S, RESP>,
options?: PoolOptions
) {
super();
// static fromOptions<
// M extends RedisModules,
// F extends RedisFunctions,
// S extends RedisScripts,
// RESP extends RespVersions,
// TYPE_MAPPING extends TypeMapping = {}
// >(
// options: RedisClientOptions<M, F, S, RESP, TYPE_MAPPING>,
// poolOptions: Partial<RedisPoolOptions>
// ) {
// 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<M, F, S, RESP, TYPE_MAPPING>,
// options?: Partial<RedisPoolOptions>
// ) {
// return new RedisClientPool(
// clientFactory,
// options
// ) as RedisClientPoolType<M, F, S, RESP, TYPE_MAPPING>;
// }
// 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<M, F, S, RESP, TYPE_MAPPING>;
// private readonly _options: Required<RedisPoolOptions>;
// private readonly _idleClients = new SinglyLinkedList<RedisClientType<M, F, S, RESP, TYPE_MAPPING>>();
// private readonly _usedClients = new DoublyLinkedList<RedisClientType<M, F, S, RESP, TYPE_MAPPING>>();
// private readonly _tasksQueue = new SinglyLinkedList<{
// resolve: <T>(value: T | PromiseLike<T>) => void;
// reject: (reason?: unknown) => void;
// fn: PoolTask<M, F, S, RESP, TYPE_MAPPING>;
// }>();
return client;
},
// TODO: destroy has to return a Promise?!
destroy: async client => client.disconnect()
}, options);
}
// constructor(
// clientFactory: () => RedisClientType<M, F, S, RESP, TYPE_MAPPING>,
// options?: Partial<RedisPoolOptions>
// ) {
// super();
execute<T>(fn: () => T): Promise<T> {
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<T>(fn: PoolTask<M, F, S, RESP, TYPE_MAPPING, T>): Promise<T> {
// return new Promise<T>((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<RedisClientType<M, F, S, RESP, TYPE_MAPPING>>,
// resolve: <T>(value: T | PromiseLike<T>) => void,
// reject: (reason?: unknown) => void,
// fn: PoolTask<M, F, S, RESP, TYPE_MAPPING>
// ) {
// 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<RedisClientType<M, F, S, RESP, TYPE_MAPPING>>) {
// 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();
// }
// }

260
test.mjs Normal file
View File

@@ -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();

232
test/package-lock.json generated Normal file
View File

@@ -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=="
}
}
}

19
test/package.json Normal file
View File

@@ -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"
}
}

26
test/test.js Normal file
View File

@@ -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);
}