Skip to content

Commit 46c7bd6

Browse files
committed
Convert to multiple match queues
1 parent 450ac4e commit 46c7bd6

File tree

5 files changed

+57
-143
lines changed

5 files changed

+57
-143
lines changed
Lines changed: 25 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,122 +1,70 @@
11
import amqplib, { Connection } from "amqplib";
22
import dotenv from "dotenv";
3-
import { matchUsers, matchUsersInQueue } from "../src/utils/mq_utils";
3+
import { matchUsers } from "../src/utils/mq_utils";
44
import { MatchRequestItem } from "../src/handlers/matchHandler";
5+
import { Complexities, Categories, Languages } from "../src/utils/constants";
56

67
dotenv.config();
78

89
let mrConnection: Connection;
9-
const queue = "match_requests";
10-
11-
let mrConnectionNew: Connection;
1210
const queues: string[] = [];
13-
14-
enum Complexities {
15-
EASY = "Easy",
16-
MEDIUM = "Medium",
17-
HARD = "Hard",
18-
}
19-
20-
enum Categories {
21-
STRINGS = "Strings",
22-
ALGORITHMS = "Algorithms",
23-
DATA_STRUCTURES = "Data Structures",
24-
BIT_MANIPULATION = "Bit Manipulation",
25-
RECURSION = "Recursion",
26-
DYNAMIC_PROGRAMMING = "Dynamic Programming",
27-
ARRAYS = "Arrays",
28-
TREE = "Tree",
29-
}
30-
31-
enum LANGUAGES {
32-
PYTHON = "Python",
33-
JAVA = "Java",
34-
C = "C",
35-
}
36-
37-
export const pendingRequestsPerQueue = new Map<
38-
string,
39-
Map<string, MatchRequestItem>
40-
>();
11+
const pendingQueueRequests = new Map<string, Map<string, MatchRequestItem>>();
4112

4213
const initQueueNames = () => {
4314
for (const complexity of Object.values(Complexities)) {
4415
for (const category of Object.values(Categories)) {
45-
for (const language of Object.values(LANGUAGES)) {
16+
for (const language of Object.values(Languages)) {
4617
queues.push(`${complexity}_${category}_${language}`);
4718
}
4819
}
4920
}
5021
};
5122

52-
export const connectToRabbitMq = async () => {
53-
try {
54-
initQueueNames();
55-
mrConnectionNew = await amqplib.connect(`${process.env.RABBITMQ_ADDR}`);
56-
for (const queue of queues) {
57-
await setUpQueue(queue);
58-
pendingRequestsPerQueue.set(queue, new Map<string, MatchRequestItem>());
59-
}
60-
} catch (error) {
61-
console.error(error);
62-
process.exit(1);
63-
}
64-
};
65-
6623
const setUpQueue = async (queueName: string) => {
67-
const consumerChannel = await mrConnectionNew.createChannel();
24+
const consumerChannel = await mrConnection.createChannel();
6825
await consumerChannel.assertQueue(queueName);
6926

7027
consumerChannel.consume(queueName, (msg) => {
71-
console.log(`consume from queue: ${queueName}`);
7228
if (msg !== null) {
73-
matchUsersInQueue(queueName, msg.content.toString());
29+
matchUsers(queueName, msg.content.toString());
7430
consumerChannel.ack(msg);
7531
}
7632
});
7733
};
7834

79-
export const sendToQueue = async (data: MatchRequestItem) => {
80-
try {
81-
const queueName = `${data.complexities[0]}_${data.categories[0]}_${data.languages[0]}`;
82-
const senderChannel = await mrConnectionNew.createChannel();
83-
senderChannel.sendToQueue(queueName, Buffer.from(JSON.stringify(data)));
84-
return true;
85-
} catch (error) {
86-
console.log(error);
87-
return false;
88-
}
89-
};
90-
91-
// ----------------
92-
93-
export const connectRabbitMq = async () => {
35+
export const connectToRabbitMq = async () => {
9436
try {
37+
initQueueNames();
9538
mrConnection = await amqplib.connect(`${process.env.RABBITMQ_ADDR}`);
96-
const consumerChannel = await mrConnection.createChannel();
97-
await consumerChannel.assertQueue(queue);
98-
99-
consumerChannel.consume(queue, (msg) => {
100-
if (msg !== null) {
101-
matchUsers(msg.content.toString());
102-
consumerChannel.ack(msg);
103-
}
104-
});
39+
for (const queue of queues) {
40+
await setUpQueue(queue);
41+
pendingQueueRequests.set(queue, new Map<string, MatchRequestItem>());
42+
}
10543
} catch (error) {
10644
console.error(error);
10745
process.exit(1);
10846
}
10947
};
11048

111-
export const sendRabbitMq = async (
49+
export const sendToQueue = async (
50+
complexity: string,
51+
category: string,
52+
language: string,
11253
data: MatchRequestItem
113-
): Promise<boolean> => {
54+
) => {
11455
try {
56+
const queueName = `${complexity}_${category}_${language}`;
11557
const senderChannel = await mrConnection.createChannel();
116-
senderChannel.sendToQueue(queue, Buffer.from(JSON.stringify(data)));
58+
senderChannel.sendToQueue(queueName, Buffer.from(JSON.stringify(data)));
11759
return true;
11860
} catch (error) {
11961
console.log(error);
12062
return false;
12163
}
12264
};
65+
66+
export const getPendingRequests = (
67+
queueName: string
68+
): Map<string, MatchRequestItem> => {
69+
return pendingQueueRequests.get(queueName)!;
70+
};

backend/matching-service/src/handlers/matchHandler.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,6 @@ export interface MatchRequest {
2525
export interface MatchRequestItem {
2626
id: string;
2727
user: MatchUser;
28-
complexities: string[];
29-
categories: string[];
30-
languages: string[];
3128
sentTimestamp: number;
3229
ttlInSecs: number;
3330
rejectedPartnerId?: string;
@@ -45,15 +42,17 @@ export const sendMatchRequest = async (
4542
const matchItem: MatchRequestItem = {
4643
id: requestId,
4744
user: user,
48-
complexities: complexities,
49-
categories: categories,
50-
languages: languages,
5145
sentTimestamp: Date.now(),
5246
ttlInSecs: timeout,
5347
rejectedPartnerId: rejectedPartnerId,
5448
};
5549

56-
const sent = await sendToQueue(matchItem);
50+
const sent = await sendToQueue(
51+
complexities[0],
52+
categories[0],
53+
languages[0],
54+
matchItem
55+
);
5756
return sent;
5857
};
5958

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
export enum Complexities {
2+
EASY = "Easy",
3+
MEDIUM = "Medium",
4+
HARD = "Hard",
5+
}
6+
7+
export enum Categories {
8+
STRINGS = "Strings",
9+
ALGORITHMS = "Algorithms",
10+
DATA_STRUCTURES = "Data Structures",
11+
BIT_MANIPULATION = "Bit Manipulation",
12+
RECURSION = "Recursion",
13+
DYNAMIC_PROGRAMMING = "Dynamic Programming",
14+
ARRAYS = "Arrays",
15+
TREE = "Tree",
16+
}
17+
18+
export enum Languages {
19+
PYTHON = "Python",
20+
JAVA = "Java",
21+
C = "C",
22+
}
Lines changed: 3 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import { pendingRequestsPerQueue } from "../../config/rabbitmq";
1+
import { getPendingRequests } from "../../config/rabbitmq";
22
import { createMatch, MatchRequestItem } from "../handlers/matchHandler";
33
import { isActiveRequest, isUserConnected } from "../handlers/websocketHandler";
44

5-
export const matchUsersInQueue = (queueName: string, newRequest: string) => {
6-
const pendingRequests = pendingRequestsPerQueue.get(queueName)!;
5+
export const matchUsers = (queueName: string, newRequest: string) => {
6+
const pendingRequests = getPendingRequests(queueName);
77
const newRequestJson = JSON.parse(newRequest) as MatchRequestItem;
88
const newRequestUid = newRequestJson.user.id;
99

@@ -40,61 +40,6 @@ export const matchUsersInQueue = (queueName: string, newRequest: string) => {
4040
pendingRequests.set(newRequestUid, newRequestJson);
4141
};
4242

43-
// ----------------
44-
45-
const matchingRequests = new Map<string, MatchRequestItem>();
46-
47-
export const matchUsers = (newRequest: string) => {
48-
const newRequestJson = JSON.parse(newRequest) as MatchRequestItem;
49-
const newRequestUid = newRequestJson.user.id;
50-
for (const [uid, pendingRequest] of matchingRequests) {
51-
if (
52-
isExpired(pendingRequest) ||
53-
!isUserConnected(uid) ||
54-
!isActiveRequest(uid, pendingRequest.id) ||
55-
uid === newRequestUid
56-
) {
57-
matchingRequests.delete(uid);
58-
continue;
59-
}
60-
if (
61-
isExpired(newRequestJson) ||
62-
!isUserConnected(newRequestUid) ||
63-
!isActiveRequest(newRequestUid, newRequestJson.id)
64-
) {
65-
return;
66-
}
67-
68-
if (
69-
uid === newRequestJson.rejectedPartnerId ||
70-
newRequestUid === pendingRequest.rejectedPartnerId
71-
) {
72-
continue;
73-
}
74-
75-
if (isMatch(newRequestJson, pendingRequest)) {
76-
matchingRequests.delete(uid);
77-
createMatch(pendingRequest, newRequestJson);
78-
return;
79-
}
80-
}
81-
matchingRequests.set(newRequestUid, newRequestJson);
82-
};
83-
8443
const isExpired = (data: MatchRequestItem): boolean => {
8544
return Date.now() - data.sentTimestamp >= data.ttlInSecs * 1000;
8645
};
87-
88-
const isMatch = (req1: MatchRequestItem, req2: MatchRequestItem): boolean => {
89-
const hasCommonComplexity = req1.complexities.some((elem) =>
90-
req2.complexities.includes(elem)
91-
);
92-
const hasCommonCategory = req1.categories.some((elem) =>
93-
req2.categories.includes(elem)
94-
);
95-
const hasCommonLanguage = req1.languages.some((elem) =>
96-
req2.languages.includes(elem)
97-
);
98-
99-
return hasCommonComplexity && hasCommonCategory && hasCommonLanguage;
100-
};

frontend/src/utils/constants.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* Dropdowns */
22
export const complexityList: string[] = ["Easy", "Medium", "Hard"];
3-
export const languageList = ["Python", "Java"];
3+
export const languageList = ["Python", "Java", "C"];
44

55
/* Context Provider Errors */
66
export const USE_AUTH_ERROR_MESSAGE =

0 commit comments

Comments
 (0)