Skip to content

Commit 393ded4

Browse files
refactor(brokers): make option props more correct (discordjs#10242)
* refactor(brokers): make option props more correct BREAKING CHANGE: Classes now take redis client as standalone parameter, various props from the base option interface moved to redis options * chore: update comment --------- Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
1 parent 20258f9 commit 393ded4

File tree

6 files changed

+53
-52
lines changed

6 files changed

+53
-52
lines changed

packages/brokers/README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ pnpm add @discordjs/brokers
4040
import { PubSubRedisBroker } from '@discordjs/brokers';
4141
import Redis from 'ioredis';
4242

43-
const broker = new PubSubRedisBroker({ redisClient: new Redis() });
43+
const broker = new PubSubRedisBroker(new Redis());
4444

4545
await broker.publish('test', 'Hello World!');
4646
await broker.destroy();
@@ -49,7 +49,7 @@ await broker.destroy();
4949
import { PubSubRedisBroker } from '@discordjs/brokers';
5050
import Redis from 'ioredis';
5151

52-
const broker = new PubSubRedisBroker({ redisClient: new Redis() });
52+
const broker = new PubSubRedisBroker(new Redis());
5353
broker.on('test', ({ data, ack }) => {
5454
console.log(data);
5555
void ack();
@@ -65,7 +65,7 @@ await broker.subscribe('subscribers', ['test']);
6565
import { RPCRedisBroker } from '@discordjs/brokers';
6666
import Redis from 'ioredis';
6767

68-
const broker = new RPCRedisBroker({ redisClient: new Redis() });
68+
const broker = new RPCRedisBroker(new Redis());
6969

7070
console.log(await broker.call('testcall', 'Hello World!'));
7171
await broker.destroy();
@@ -74,7 +74,7 @@ await broker.destroy();
7474
import { RPCRedisBroker } from '@discordjs/brokers';
7575
import Redis from 'ioredis';
7676

77-
const broker = new RPCRedisBroker({ redisClient: new Redis() });
77+
const broker = new RPCRedisBroker(new Redis());
7878
broker.on('testcall', ({ data, ack, reply }) => {
7979
console.log('responder', data);
8080
void ack();

packages/brokers/__tests__/index.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ const mockRedisClient = {
1717
test('pubsub with custom encoding', async () => {
1818
const encode = vi.fn((data) => data);
1919

20-
const broker = new PubSubRedisBroker({ redisClient: mockRedisClient, encode });
20+
const broker = new PubSubRedisBroker(mockRedisClient, { encode });
2121
await broker.publish('test', 'test');
2222
expect(encode).toHaveBeenCalledWith('test');
2323
});

packages/brokers/src/brokers/Broker.ts

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,11 @@
11
import { Buffer } from 'node:buffer';
2-
import { randomBytes } from 'node:crypto';
32
import { encode, decode } from '@msgpack/msgpack';
43
import type { AsyncEventEmitter } from '@vladfrangu/async_event_emitter';
54

65
/**
76
* Base options for a broker implementation
87
*/
98
export interface BaseBrokerOptions {
10-
/**
11-
* How long to block for messages when polling
12-
*/
13-
blockTimeout?: number;
149
/**
1510
* Function to use for decoding messages
1611
*/
@@ -21,25 +16,12 @@ export interface BaseBrokerOptions {
2116
*/
2217
// eslint-disable-next-line @typescript-eslint/method-signature-style
2318
encode?: (data: unknown) => Buffer;
24-
/**
25-
* Max number of messages to poll at once
26-
*/
27-
maxChunk?: number;
28-
/**
29-
* Unique consumer name.
30-
*
31-
* @see {@link https://redis.io/commands/xreadgroup/}
32-
*/
33-
name?: string;
3419
}
3520

3621
/**
3722
* Default broker options
3823
*/
3924
export const DefaultBrokerOptions = {
40-
name: randomBytes(20).toString('hex'),
41-
maxChunk: 10,
42-
blockTimeout: 5_000,
4325
encode: (data): Buffer => {
4426
const encoded = encode(data);
4527
return Buffer.from(encoded.buffer, encoded.byteOffset, encoded.byteLength);

packages/brokers/src/brokers/redis/BaseRedis.ts

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { Buffer } from 'node:buffer';
2+
import { randomBytes } from 'node:crypto';
23
import { readFileSync } from 'node:fs';
34
import { resolve } from 'node:path';
45
import { AsyncEventEmitter } from '@vladfrangu/async_event_emitter';
@@ -19,11 +20,31 @@ declare module 'ioredis' {
1920
*/
2021
export interface RedisBrokerOptions extends BaseBrokerOptions {
2122
/**
22-
* The Redis client to use
23+
* How long to block for messages when polling
2324
*/
24-
redisClient: Redis;
25+
blockTimeout?: number;
26+
/**
27+
* Max number of messages to poll at once
28+
*/
29+
maxChunk?: number;
30+
/**
31+
* Unique consumer name.
32+
*
33+
* @see {@link https://redis.io/commands/xreadgroup/}
34+
*/
35+
name?: string;
2536
}
2637

38+
/**
39+
* Default broker options for redis
40+
*/
41+
export const DefaultRedisBrokerOptions = {
42+
...DefaultBrokerOptions,
43+
name: randomBytes(20).toString('hex'),
44+
maxChunk: 10,
45+
blockTimeout: 5_000,
46+
} as const satisfies Required<RedisBrokerOptions>;
47+
2748
/**
2849
* Helper class with shared Redis logic
2950
*/
@@ -56,14 +77,17 @@ export abstract class BaseRedisBroker<TEvents extends Record<string, any>>
5677
*/
5778
protected listening = false;
5879

59-
public constructor(options: RedisBrokerOptions) {
80+
public constructor(
81+
protected readonly redisClient: Redis,
82+
options: RedisBrokerOptions,
83+
) {
6084
super();
61-
this.options = { ...DefaultBrokerOptions, ...options };
62-
options.redisClient.defineCommand('xcleangroup', {
85+
this.options = { ...DefaultRedisBrokerOptions, ...options };
86+
redisClient.defineCommand('xcleangroup', {
6387
numberOfKeys: 1,
6488
lua: readFileSync(resolve(__dirname, '..', 'scripts', 'xcleangroup.lua'), 'utf8'),
6589
});
66-
this.streamReadClient = options.redisClient.duplicate();
90+
this.streamReadClient = redisClient.duplicate();
6791
}
6892

6993
/**
@@ -75,7 +99,7 @@ export abstract class BaseRedisBroker<TEvents extends Record<string, any>>
7599
events.map(async (event) => {
76100
this.subscribedEvents.add(event as string);
77101
try {
78-
return await this.options.redisClient.xgroup('CREATE', event as string, group, 0, 'MKSTREAM');
102+
return await this.redisClient.xgroup('CREATE', event as string, group, 0, 'MKSTREAM');
79103
} catch (error) {
80104
if (!(error instanceof ReplyError)) {
81105
throw error;
@@ -97,7 +121,7 @@ export abstract class BaseRedisBroker<TEvents extends Record<string, any>>
97121
commands[idx + 1] = ['xcleangroup', event as string, group];
98122
}
99123

100-
await this.options.redisClient.pipeline(commands).exec();
124+
await this.redisClient.pipeline(commands).exec();
101125

102126
for (const event of events) {
103127
this.subscribedEvents.delete(event as string);
@@ -162,7 +186,7 @@ export abstract class BaseRedisBroker<TEvents extends Record<string, any>>
162186
*/
163187
public async destroy() {
164188
this.streamReadClient.disconnect();
165-
this.options.redisClient.disconnect();
189+
this.redisClient.disconnect();
166190
}
167191

168192
/**

packages/brokers/src/brokers/redis/PubSubRedis.ts

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { BaseRedisBroker } from './BaseRedis.js';
1111
* import { PubSubRedisBroker } from '@discordjs/brokers';
1212
* import Redis from 'ioredis';
1313
*
14-
* const broker = new PubSubRedisBroker({ redisClient: new Redis() });
14+
* const broker = new PubSubRedisBroker(new Redis());
1515
*
1616
* await broker.publish('test', 'Hello World!');
1717
* await broker.destroy();
@@ -20,7 +20,7 @@ import { BaseRedisBroker } from './BaseRedis.js';
2020
* import { PubSubRedisBroker } from '@discordjs/brokers';
2121
* import Redis from 'ioredis';
2222
*
23-
* const broker = new PubSubRedisBroker({ redisClient: new Redis() });
23+
* const broker = new PubSubRedisBroker(new Redis());
2424
* broker.on('test', ({ data, ack }) => {
2525
* console.log(data);
2626
* void ack();
@@ -37,19 +37,14 @@ export class PubSubRedisBroker<TEvents extends Record<string, any>>
3737
* {@inheritDoc IPubSubBroker.publish}
3838
*/
3939
public async publish<Event extends keyof TEvents>(event: Event, data: TEvents[Event]): Promise<void> {
40-
await this.options.redisClient.xadd(
41-
event as string,
42-
'*',
43-
BaseRedisBroker.STREAM_DATA_KEY,
44-
this.options.encode(data),
45-
);
40+
await this.redisClient.xadd(event as string, '*', BaseRedisBroker.STREAM_DATA_KEY, this.options.encode(data));
4641
}
4742

4843
protected emitEvent(id: Buffer, group: string, event: string, data: unknown) {
4944
const payload: { ack(): Promise<void>; data: unknown } = {
5045
data,
5146
ack: async () => {
52-
await this.options.redisClient.xack(event, group, id);
47+
await this.redisClient.xack(event, group, id);
5348
},
5449
};
5550

packages/brokers/src/brokers/redis/RPCRedis.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import type { Buffer } from 'node:buffer';
22
import { clearTimeout, setTimeout } from 'node:timers';
3+
import type Redis from 'ioredis/built/Redis.js';
34
import type { IRPCBroker } from '../Broker.js';
4-
import { DefaultBrokerOptions } from '../Broker.js';
55
import type { RedisBrokerOptions } from './BaseRedis.js';
6-
import { BaseRedisBroker } from './BaseRedis.js';
6+
import { BaseRedisBroker, DefaultRedisBrokerOptions } from './BaseRedis.js';
77

88
interface InternalPromise {
99
reject(error: any): void;
@@ -22,9 +22,9 @@ export interface RPCRedisBrokerOptions extends RedisBrokerOptions {
2222
* Default values used for the {@link RPCRedisBrokerOptions}
2323
*/
2424
export const DefaultRPCRedisBrokerOptions = {
25-
...DefaultBrokerOptions,
25+
...DefaultRedisBrokerOptions,
2626
timeout: 5_000,
27-
} as const satisfies Required<Omit<RPCRedisBrokerOptions, 'redisClient'>>;
27+
} as const satisfies Required<RPCRedisBrokerOptions>;
2828

2929
/**
3030
* RPC broker powered by Redis
@@ -35,7 +35,7 @@ export const DefaultRPCRedisBrokerOptions = {
3535
* import { RPCRedisBroker } from '@discordjs/brokers';
3636
* import Redis from 'ioredis';
3737
*
38-
* const broker = new RPCRedisBroker({ redisClient: new Redis() });
38+
* const broker = new RPCRedisBroker(new Redis());
3939
*
4040
* console.log(await broker.call('testcall', 'Hello World!'));
4141
* await broker.destroy();
@@ -44,7 +44,7 @@ export const DefaultRPCRedisBrokerOptions = {
4444
* import { RPCRedisBroker } from '@discordjs/brokers';
4545
* import Redis from 'ioredis';
4646
*
47-
* const broker = new RPCRedisBroker({ redisClient: new Redis() });
47+
* const broker = new RPCRedisBroker(new Redis());
4848
* broker.on('testcall', ({ data, ack, reply }) => {
4949
* console.log('responder', data);
5050
* void ack();
@@ -65,8 +65,8 @@ export class RPCRedisBroker<TEvents extends Record<string, any>, TResponses exte
6565

6666
protected readonly promises = new Map<string, InternalPromise>();
6767

68-
public constructor(options: RPCRedisBrokerOptions) {
69-
super(options);
68+
public constructor(redisClient: Redis, options: RPCRedisBrokerOptions) {
69+
super(redisClient, options);
7070
this.options = { ...DefaultRPCRedisBrokerOptions, ...options };
7171

7272
this.streamReadClient.on('messageBuffer', (channel: Buffer, message: Buffer) => {
@@ -88,7 +88,7 @@ export class RPCRedisBroker<TEvents extends Record<string, any>, TResponses exte
8888
data: TEvents[Event],
8989
timeoutDuration: number = this.options.timeout,
9090
): Promise<TResponses[Event]> {
91-
const id = await this.options.redisClient.xadd(
91+
const id = await this.redisClient.xadd(
9292
event as string,
9393
'*',
9494
BaseRedisBroker.STREAM_DATA_KEY,
@@ -118,10 +118,10 @@ export class RPCRedisBroker<TEvents extends Record<string, any>, TResponses exte
118118
const payload: { ack(): Promise<void>; data: unknown; reply(data: unknown): Promise<void> } = {
119119
data,
120120
ack: async () => {
121-
await this.options.redisClient.xack(event, group, id);
121+
await this.redisClient.xack(event, group, id);
122122
},
123123
reply: async (data) => {
124-
await this.options.redisClient.publish(`${event}:${id.toString()}`, this.options.encode(data));
124+
await this.redisClient.publish(`${event}:${id.toString()}`, this.options.encode(data));
125125
},
126126
};
127127

0 commit comments

Comments
 (0)