Skip to content

Commit 645dfd1

Browse files
fix(microservices) add subscriptions counter to mqtt and redis
1 parent c4f80bd commit 645dfd1

3 files changed

Lines changed: 55 additions & 17 deletions

File tree

integration/microservices/e2e/sum-mqtt.spec.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,7 @@ describe('MQTT transport', () => {
4949
.expect(200, '15');
5050
});
5151

52-
/**
53-
* Figure out race conditions here (flaky tests)
5452
it(`/POST (concurrent)`, function() {
55-
this.retries(10);
5653
return request(server)
5754
.post('/concurrent')
5855
.send([
@@ -68,7 +65,7 @@ describe('MQTT transport', () => {
6865
Array.from({ length: 10 }, (v, k) => k + 91),
6966
])
7067
.expect(200, 'true');
71-
}).timeout(5000); */
68+
}).timeout(5000);
7269

7370
it(`/POST (streaming)`, () => {
7471
return request(server)

packages/microservices/client/client-mqtt.ts

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ let mqttPackage: any = {};
1717

1818
export class ClientMqtt extends ClientProxy {
1919
protected readonly logger = new Logger(ClientProxy.name);
20+
protected readonly subscriptionsCount = new Map<string, number>();
2021
protected readonly url: string;
2122
protected mqttClient: MqttClient;
2223
protected connection: Promise<any>;
@@ -121,19 +122,30 @@ export class ClientMqtt extends ClientProxy {
121122
const pattern = this.normalizePattern(partialPacket.pattern);
122123
const serializedPacket = this.serializer.serialize(packet);
123124
const responseChannel = this.getResPatternName(pattern);
125+
let subscriptionsCount =
126+
this.subscriptionsCount.get(responseChannel) || 0;
124127

125-
this.mqttClient.subscribe(responseChannel, (err: any) => {
126-
if (err) {
127-
return;
128-
}
128+
const publishPacket = () => {
129+
subscriptionsCount = this.subscriptionsCount.get(responseChannel) || 0;
130+
this.subscriptionsCount.set(responseChannel, subscriptionsCount + 1);
129131
this.routingMap.set(packet.id, callback);
130132
this.mqttClient.publish(
131133
this.getAckPatternName(pattern),
132134
JSON.stringify(serializedPacket),
133135
);
134-
});
136+
};
137+
138+
if (subscriptionsCount <= 0) {
139+
this.mqttClient.subscribe(
140+
responseChannel,
141+
(err: any) => !err && publishPacket(),
142+
);
143+
} else {
144+
publishPacket();
145+
}
146+
135147
return () => {
136-
this.mqttClient.unsubscribe(responseChannel);
148+
this.unsubscribeFromChannel(responseChannel);
137149
this.routingMap.delete(packet.id);
138150
};
139151
} catch (err) {
@@ -151,4 +163,13 @@ export class ClientMqtt extends ClientProxy {
151163
),
152164
);
153165
}
166+
167+
protected unsubscribeFromChannel(channel: string) {
168+
const subscriptionCount = this.subscriptionsCount.get(channel);
169+
this.subscriptionsCount.set(channel, subscriptionCount - 1);
170+
171+
if (subscriptionCount - 1 <= 0) {
172+
this.mqttClient.unsubscribe(channel);
173+
}
174+
}
154175
}

packages/microservices/client/client-redis.ts

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ let redisPackage: any = {};
2121

2222
export class ClientRedis extends ClientProxy {
2323
protected readonly logger = new Logger(ClientProxy.name);
24+
protected readonly subscriptionsCount = new Map<string, number>();
2425
protected readonly url: string;
2526
protected pubClient: RedisClient;
2627
protected subClient: RedisClient;
@@ -152,20 +153,30 @@ export class ClientRedis extends ClientProxy {
152153
const pattern = this.normalizePattern(partialPacket.pattern);
153154
const serializedPacket = this.serializer.serialize(packet);
154155
const responseChannel = this.getResPatternName(pattern);
156+
let subscriptionsCount =
157+
this.subscriptionsCount.get(responseChannel) || 0;
155158

156-
this.routingMap.set(packet.id, callback);
157-
this.subClient.subscribe(responseChannel, (err: any) => {
158-
if (err) {
159-
return;
160-
}
159+
const publishPacket = () => {
160+
subscriptionsCount = this.subscriptionsCount.get(responseChannel) || 0;
161+
this.subscriptionsCount.set(responseChannel, subscriptionsCount + 1);
162+
this.routingMap.set(packet.id, callback);
161163
this.pubClient.publish(
162164
this.getAckPatternName(pattern),
163165
JSON.stringify(serializedPacket),
164166
);
165-
});
167+
};
168+
169+
if (subscriptionsCount <= 0) {
170+
this.subClient.subscribe(
171+
responseChannel,
172+
(err: any) => !err && publishPacket(),
173+
);
174+
} else {
175+
publishPacket();
176+
}
166177

167178
return () => {
168-
this.subClient.unsubscribe(responseChannel);
179+
this.unsubscribeFromChannel(responseChannel);
169180
this.routingMap.delete(packet.id);
170181
};
171182
} catch (err) {
@@ -183,4 +194,13 @@ export class ClientRedis extends ClientProxy {
183194
),
184195
);
185196
}
197+
198+
protected unsubscribeFromChannel(channel: string) {
199+
const subscriptionCount = this.subscriptionsCount.get(channel);
200+
this.subscriptionsCount.set(channel, subscriptionCount - 1);
201+
202+
if (subscriptionCount - 1 <= 0) {
203+
this.subClient.unsubscribe(channel);
204+
}
205+
}
186206
}

0 commit comments

Comments
 (0)