Skip to content

Commit 6059b1e

Browse files
committed
Merge branch 'v5' of github.com:leibale/node-redis into v5
2 parents 699b6f0 + 437f76c commit 6059b1e

File tree

7 files changed

+790
-85
lines changed

7 files changed

+790
-85
lines changed

benchmark/lib/ping/local-resp3-module-with-flags.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ export default async (host) => {
1818

1919
return {
2020
benchmark() {
21-
return client.withFlags({}).module.ping();
21+
return client.withTypeMapping({}).module.ping();
2222
},
2323
teardown() {
2424
return client.disconnect();

docs/todo.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
# Leibale
2+
3+
- Does `close`/`destory` actually close the connection from the Redis POV? Works with OSS, but what about Redis Enterprie?
4+
5+
# Docs
6+
7+
- [v4 to v5](./v4-to-v5.md) - Legacy mode
8+
- [Command Options](./command-options.md)
9+
- [RESP](./RESP.md)
10+
111
# Missing functionality
212

313
- `HEXISTS`: accepts one field only, should be the same as `EXISTS`

packages/client/lib/client/pool.ts

Lines changed: 242 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,84 +1,242 @@
1-
import { Pool, Options as PoolOptions, createPool } from 'generic-pool';
2-
import { RedisFunctions, RedisModules, RedisScripts, RespVersions } from '../RESP/types';
3-
import RedisClient, { RedisClientType, RedisClientOptions } from '.';
4-
import { EventEmitter } from 'events';
5-
6-
type RedisClientPoolOptions<
7-
M extends RedisModules,
8-
F extends RedisFunctions,
9-
S extends RedisScripts,
10-
RESP extends RespVersions
11-
> = RedisClientOptions<M, F, S, RESP> & PoolOptions;
12-
13-
export class RedisClientPool<
14-
M extends RedisModules,
15-
F extends RedisFunctions,
16-
S extends RedisScripts,
17-
RESP extends RespVersions
18-
> extends EventEmitter {
19-
_pool: Pool<RedisClientType<M, F, S, RESP>>;
20-
21-
static fromClient<
22-
M extends RedisModules,
23-
F extends RedisFunctions,
24-
S extends RedisScripts,
25-
RESP extends RespVersions
26-
>(
27-
client: RedisClientType<M, F, S, RESP>,
28-
poolOptions?: PoolOptions
29-
) {
30-
return new RedisClientPool<M, F, S, RESP>(
31-
() => client.duplicate(),
32-
poolOptions
33-
);
34-
}
35-
36-
static fromOptions<
37-
M extends RedisModules,
38-
F extends RedisFunctions,
39-
S extends RedisScripts,
40-
RESP extends RespVersions
41-
>(
42-
options: RedisClientPoolOptions<M, F, S, RESP>,
43-
poolOptions?: PoolOptions
44-
) {
45-
return new RedisClientPool(
46-
RedisClient.factory(options),
47-
poolOptions
48-
);
49-
}
50-
51-
constructor(
52-
clientFactory: () => RedisClientType<M, F, S, RESP>,
53-
options?: PoolOptions
54-
) {
55-
super();
56-
57-
this._pool = createPool({
58-
create: async () => {
59-
const client = clientFactory();
60-
61-
// TODO: more events?
62-
client.on('error', (err: Error) => this.emit('error', err));
63-
64-
await client.connect();
65-
66-
return client;
67-
},
68-
// TODO: destroy has to return a Promise?!
69-
destroy: async client => client.disconnect()
70-
}, options);
71-
}
72-
73-
execute<T>(fn: () => T): Promise<T> {
74-
return this._pool.use(fn);
75-
}
76-
77-
close() {
78-
// TODO
79-
}
80-
81-
disconnect() {
82-
// TODO
83-
}
84-
}
1+
// import COMMANDS from '../commands';
2+
// import { RedisFunctions, RedisModules, RedisScripts, RespVersions, TypeMapping } from '../RESP/types';
3+
// import RedisClient, { RedisClientType, RedisClientOptions, RedisClientExtensions } from '.';
4+
// import { EventEmitter } from 'events';
5+
// import { DoublyLinkedNode, DoublyLinkedList, SinglyLinkedList } from './linked-list';
6+
7+
// export type RedisPoolOptions = typeof RedisClientPool['_DEFAULTS'];
8+
9+
// export type PoolTask<
10+
// M extends RedisModules,
11+
// F extends RedisFunctions,
12+
// S extends RedisScripts,
13+
// RESP extends RespVersions,
14+
// TYPE_MAPPING extends TypeMapping,
15+
// T = unknown
16+
// > = (client: RedisClientType<M, F, S, RESP, TYPE_MAPPING>) => T;
17+
18+
// export type RedisClientPoolType<
19+
// M extends RedisModules = {},
20+
// F extends RedisFunctions = {},
21+
// S extends RedisScripts = {},
22+
// RESP extends RespVersions = 2,
23+
// TYPE_MAPPING extends TypeMapping = {}
24+
// > = (
25+
// RedisClientPool<M, F, S, RESP, TYPE_MAPPING> &
26+
// RedisClientExtensions<M, F, S, RESP, TYPE_MAPPING>
27+
// );
28+
29+
// export class RedisClientPool<
30+
// M extends RedisModules = {},
31+
// F extends RedisFunctions = {},
32+
// S extends RedisScripts = {},
33+
// RESP extends RespVersions = 2,
34+
// TYPE_MAPPING extends TypeMapping = {}
35+
// > extends EventEmitter {
36+
// static fromClient<
37+
// M extends RedisModules,
38+
// F extends RedisFunctions,
39+
// S extends RedisScripts,
40+
// RESP extends RespVersions,
41+
// TYPE_MAPPING extends TypeMapping = {}
42+
// >(
43+
// client: RedisClientType<M, F, S, RESP, TYPE_MAPPING>,
44+
// poolOptions: Partial<RedisPoolOptions>
45+
// ) {
46+
// return RedisClientPool.create(
47+
// () => client.duplicate(),
48+
// poolOptions
49+
// );
50+
// }
51+
52+
// static fromOptions<
53+
// M extends RedisModules,
54+
// F extends RedisFunctions,
55+
// S extends RedisScripts,
56+
// RESP extends RespVersions,
57+
// TYPE_MAPPING extends TypeMapping = {}
58+
// >(
59+
// options: RedisClientOptions<M, F, S, RESP, TYPE_MAPPING>,
60+
// poolOptions: Partial<RedisPoolOptions>
61+
// ) {
62+
// return RedisClientPool.create(
63+
// RedisClient.factory(options),
64+
// poolOptions
65+
// );
66+
// }
67+
68+
// static create<
69+
// M extends RedisModules,
70+
// F extends RedisFunctions,
71+
// S extends RedisScripts,
72+
// RESP extends RespVersions,
73+
// TYPE_MAPPING extends TypeMapping = {}
74+
// >(
75+
// clientFactory: () => RedisClientType<M, F, S, RESP, TYPE_MAPPING>,
76+
// options?: Partial<RedisPoolOptions>
77+
// ) {
78+
// return new RedisClientPool(
79+
// clientFactory,
80+
// options
81+
// ) as RedisClientPoolType<M, F, S, RESP, TYPE_MAPPING>;
82+
// }
83+
84+
// private static _DEFAULTS = {
85+
// /**
86+
// * The minimum number of clients to keep in the pool.
87+
// */
88+
// minimum: 0,
89+
// /**
90+
// * The maximum number of clients to keep in the pool.
91+
// */
92+
// maximum: 1,
93+
// /**
94+
// * The maximum time a task can wait for a client to become available.
95+
// */
96+
// acquireTimeout: 3000,
97+
// /**
98+
// * When there are `> minimum && < maximum` clients in the pool, the pool will wait for `cleanupDelay` milliseconds before closing the extra clients.
99+
// */
100+
// cleanupDelay: 3000
101+
// };
102+
103+
// private readonly _clientFactory: () => RedisClientType<M, F, S, RESP, TYPE_MAPPING>;
104+
// private readonly _options: Required<RedisPoolOptions>;
105+
// private readonly _idleClients = new SinglyLinkedList<RedisClientType<M, F, S, RESP, TYPE_MAPPING>>();
106+
// private readonly _usedClients = new DoublyLinkedList<RedisClientType<M, F, S, RESP, TYPE_MAPPING>>();
107+
// private readonly _tasksQueue = new SinglyLinkedList<{
108+
// resolve: <T>(value: T | PromiseLike<T>) => void;
109+
// reject: (reason?: unknown) => void;
110+
// fn: PoolTask<M, F, S, RESP, TYPE_MAPPING>;
111+
// }>();
112+
113+
// constructor(
114+
// clientFactory: () => RedisClientType<M, F, S, RESP, TYPE_MAPPING>,
115+
// options?: Partial<RedisPoolOptions>
116+
// ) {
117+
// super();
118+
119+
// this._clientFactory = clientFactory;
120+
// this._options = {
121+
// ...RedisClientPool._DEFAULTS,
122+
// ...options
123+
// };
124+
// this._initate();
125+
// }
126+
127+
// private async _initate() {
128+
// const promises = [];
129+
// while (promises.length < this._options.minimum) {
130+
// promises.push(this._create());
131+
// }
132+
133+
// try {
134+
// await Promise.all(promises);
135+
// } catch (err) {
136+
// this.destroy();
137+
// this.emit('error', err);
138+
// }
139+
// }
140+
141+
// private async _create() {
142+
// const client = this._clientFactory()
143+
// // TODO: more events?
144+
// .on('error', (err: Error) => this.emit('error', err));
145+
146+
// const node = this._usedClients.push(client);
147+
148+
// await client.connect();
149+
150+
// this._usedClients.remove(node);
151+
152+
// return client;
153+
// }
154+
155+
// execute<T>(fn: PoolTask<M, F, S, RESP, TYPE_MAPPING, T>): Promise<T> {
156+
// return new Promise<T>((resolve, reject) => {
157+
// let client = this._idleClients.shift();
158+
// if (!client) {
159+
// this._tasksQueue.push({
160+
// // @ts-ignore
161+
// resolve,
162+
// reject,
163+
// fn
164+
// });
165+
166+
// if (this._idleClients.length + this._usedClients.length < this._options.maximum) {
167+
// this._create();
168+
// }
169+
170+
// return;
171+
// }
172+
173+
// const node = this._usedClients.push(client);
174+
// // @ts-ignore
175+
// this._executeTask(node, resolve, reject, fn);
176+
// });
177+
// }
178+
179+
// private _executeTask(
180+
// node: DoublyLinkedNode<RedisClientType<M, F, S, RESP, TYPE_MAPPING>>,
181+
// resolve: <T>(value: T | PromiseLike<T>) => void,
182+
// reject: (reason?: unknown) => void,
183+
// fn: PoolTask<M, F, S, RESP, TYPE_MAPPING>
184+
// ) {
185+
// const result = fn(node.value);
186+
// if (result instanceof Promise) {
187+
// result.then(resolve, reject);
188+
// result.finally(() => this._returnClient(node))
189+
// } else {
190+
// resolve(result);
191+
// this._returnClient(node);
192+
// }
193+
// }
194+
195+
// private _returnClient(node: DoublyLinkedListNode<RedisClientType<M, F, S, RESP, TYPE_MAPPING>>) {
196+
// const task = this._tasksQueue.shift();
197+
// if (task) {
198+
// this._executeTask(node, task.resolve, task.reject, task.fn);
199+
// return;
200+
// }
201+
202+
// if (this._idleClients.length >= this._options.minimum) {
203+
// node.client.destroy();
204+
// return;
205+
// }
206+
207+
// this._usedClients.remove(node);
208+
// this._idleClients.push(node.client);
209+
// }
210+
211+
// async close() {
212+
// const promises = [];
213+
214+
// for (const client of this._idleClients) {
215+
// promises.push(client.close());
216+
// }
217+
218+
// this._idleClients.reset();
219+
220+
// for (const client of this._usedClients) {
221+
// promises.push(client.close());
222+
// }
223+
224+
// this._usedClients.reset();
225+
226+
// await Promise.all(promises);
227+
// }
228+
229+
// destroy() {
230+
// for (const client of this._idleClients) {
231+
// client.destroy();
232+
// }
233+
234+
// this._idleClients.reset();
235+
236+
// for (const client of this._usedClients) {
237+
// client.destroy();
238+
// }
239+
240+
// this._usedClients.reset();
241+
// }
242+
// }

0 commit comments

Comments
 (0)