Skip to content

Commit dea4987

Browse files
authored
History Service (#69)
* Initialize history service * History: Centralize env variables * History: Create model * History: Add endpoint * Collab: Add producers to trigger history * History: Add history consumers * Add tests for history service * Add GHA to history service * History: Add README * Collab: Update README * Minor fixes * Include new dependency in gateway * Fix wrong gateway route * Remove versioning * Fix typo
1 parent c00b72e commit dea4987

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+7036
-3
lines changed

.env.sample

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ COLLAB_DB_LOCAL_URI=mongodb://collaboration-db:27017/collaboration-service
2424
YJS_DB_CLOUD_URI=mongodb+srv://<username>:<password>@cluster0.h5ukw.mongodb.net/yjs-documents?retryWrites=true&w=majority&appName=Cluster0
2525
YJS_DB_LOCAL_URI=mongodb://collaboration-db:27017/yjs-documents
2626

27+
# History Service
28+
HISTORY_DB_CLOUD_URI=<FILL-THIS-IN>
29+
HISTORY_DB_LOCAL_URI=mongodb://history-db:27017/history
30+
2731
# Will use cloud MongoDB Atlas database
2832
ENV=PROD
2933

.github/workflows/tests.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,22 @@ jobs:
3636
run: cd ${{ matrix.service }} && npm run lint
3737
- name: Build App
3838
run: cd ${{ matrix.service }} && npm run build
39+
40+
41+
build-history:
42+
runs-on: ubuntu-latest
43+
timeout-minutes: 60
44+
steps:
45+
- uses: actions/checkout@v4
46+
- name: Use Node.js
47+
uses: actions/setup-node@v4
48+
with:
49+
node-version: ${{ env.node-version }}
50+
- name: Install Node Modules
51+
run: cd services/history && npm ci
52+
- name: Linting
53+
run: cd services/history && npm run lint
54+
- name: Build App
55+
run: cd services/history && npm run build
56+
- name: Run tests
57+
run: cd services/history && npm run test

compose.dev.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,22 @@ services:
5252
ports:
5353
- 27020:27017
5454

55+
collaboration-db:
56+
ports:
57+
- 27020:27017
58+
59+
history:
60+
command: npm run dev
61+
ports:
62+
- 8086:8086
63+
volumes:
64+
- /app/node_modules
65+
- ./services/history:/app
66+
67+
history-db:
68+
ports:
69+
- 27021:27017
70+
5571
broker:
5672
ports:
5773
- 5672:5672

compose.yml

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ services:
2121
- user
2222
- match
2323
- collaboration
24+
- history
2425
networks:
2526
- gateway-network
2627
restart: always
@@ -167,12 +168,39 @@ services:
167168
networks:
168169
- collaboration-db-network
169170
restart: always
171+
172+
history:
173+
container_name: history
174+
image: history
175+
build:
176+
context: services/history
177+
dockerfile: Dockerfile
178+
environment:
179+
DB_CLOUD_URI: ${HISTORY_DB_CLOUD_URI}
180+
DB_LOCAL_URI: ${HISTORY_DB_LOCAL_URI}
181+
BROKER_URL: ${BROKER_URL}
182+
JWT_SECRET: ${JWT_SECRET}
183+
depends_on:
184+
broker:
185+
condition: service_healthy
186+
networks:
187+
- gateway-network
188+
- history-db-network
189+
190+
history-db:
191+
container_name: history-db
192+
image: mongo:7.0.14
193+
volumes:
194+
- history-db:/data/db
195+
networks:
196+
- history-db-network
170197

171198
volumes:
172199
question-db:
173200
user-db:
174201
match-db:
175202
collaboration-db:
203+
history-db:
176204

177205
networks:
178206
gateway-network:
@@ -184,4 +212,6 @@ networks:
184212
match-db-network:
185213
driver: bridge
186214
collaboration-db-network:
187-
driver: bridge
215+
driver: bridge
216+
history-db-network:
217+
driver: bridge

nginx/default.conf

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ upstream collaboration-api {
1414
server collaboration:8084;
1515
}
1616

17+
upstream history-api {
18+
server history:8086;
19+
}
20+
1721
server {
1822
listen 8080;
1923
server_name localhost;
@@ -40,4 +44,9 @@ server {
4044
proxy_set_header Upgrade $http_upgrade;
4145
proxy_set_header Connection "upgrade";
4246
}
47+
48+
location /api/history {
49+
proxy_pass http://history-api;
50+
proxy_set_header Host $host;
51+
}
4352
}

services/collaboration/README.md

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -348,14 +348,16 @@ curl -X PATCH http://localhost:8080/api/collaboration/room/6724e9d892fb3e9f04c2e
348348
## Documentation on Queue (RabbitMQ)
349349

350350
The collaboration service uses RabbitMQ as a message broker to facilitate communication between microservices (such as
351-
the `matching service` and `collaboration service`) in an asynchronous manner. The system consists of a consumer and two
351+
the `matching service` and `collaboration service`) in an asynchronous manner. The system consists of a consumer and four
352352
producers:
353353

354354
### Queues Used
355355

356356
- `QUESTION_FOUND`: Handles messages related to matching users and creating collaboration rooms.
357357
- `COLLAB_CREATED`: Sends messages indicating that a collaboration room has been successfully created.
358358
- `MATCH_FAILED`: Sends messages indicating that a collaboration room could not be created.
359+
- `CREATE_HISTORY`: Sends messages requesting that user history be created for the new collaboration room.
360+
- `UPDATE_HISTORY`: Sends messages requesting that user history be updated for the new collaboration room.
359361

360362
---
361363

@@ -393,6 +395,53 @@ The producer will send a message to the `MATCH_FAILED` queue when a collaboratio
393395
}
394396
```
395397

398+
The producer will send a message to the `CREATE_HISTORY` queue when a collaboration room was created successfully.
399+
400+
- **Queue**: `CREATE_HISTORY`
401+
- **Data Produced**
402+
- `roomId` - The ID of the collaboration room.
403+
- `user1` - The first user associated with the collaboration room.
404+
- `user2` - The second user associated with the collaboration room.
405+
- `question` - The question associated with the collaboration room.
406+
407+
```json
408+
{
409+
"roomId": "67234d29aa52f2376973f96a",
410+
"user1": {
411+
"username": "user123",
412+
"_id": "671a064a6f536e9af46b0017"
413+
},
414+
"user2": {
415+
"username": "userabc",
416+
"_id": "671a06526f536e9af46b001f"
417+
},
418+
"question": {
419+
"id": 1,
420+
"title": "Roman to Integer",
421+
"description": "Given a roman numeral, convert it to an integer.",
422+
"topics": [ "Algorithms" ],
423+
"difficulty": "Easy",
424+
"_id": "671a0615dc63fe2d5f3bbae5"
425+
},
426+
},
427+
```
428+
429+
The producer will send a message to the `UPDATE_HISTORY` queue when a user forfeits or completes a collaborative session.
430+
431+
- **Queue**: `UPDATE_HISTORY`
432+
- **Data Produced**
433+
- `roomId` - The ID of the collaboration room.
434+
- `userId` - The user associated with the update.
435+
- `status` - The new status associated with the collaboration room. It may be `"IN_PROGRESS"`, `"FORFEITED"`, or `"COMPLETED"`.
436+
437+
```json
438+
{
439+
"roomId": "67234d29aa52f2376973f96a",
440+
"userId": "671a064a6f536e9af46b0017",
441+
"status": "FORFEITED"
442+
},
443+
```
444+
396445
---
397446

398447
## Consumer

services/collaboration/src/controllers/roomController.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import {
1010
} from '../services/mongodbService';
1111
import { handleHttpNotFound, handleHttpSuccess, handleHttpServerError, handleHttpBadRequest } from '../utils/helper';
1212
import { Room } from './types';
13+
import { produceUpdateHistory } from '../events/producer';
14+
import { HistoryStatus } from '../types/message';
1315

1416
export enum Difficulty {
1517
Easy = 'Easy',
@@ -96,6 +98,12 @@ export const closeRoomController = async (req: Request, res: Response) => {
9698
}
9799

98100
await deleteYjsDocument(roomId);
101+
await Promise.all(
102+
room.users
103+
.filter(user => !user.isForfeit)
104+
.map(user => produceUpdateHistory(roomId, user.id, HistoryStatus.COMPLETED)),
105+
);
106+
99107
console.log(`Room ${roomId} closed and Yjs document removed`);
100108

101109
return handleHttpSuccess(res, `Room ${roomId} successfully closed`);
@@ -130,6 +138,7 @@ export const updateUserStatusInRoomController = async (req: Request, res: Respon
130138
return handleHttpNotFound(res, 'User not found in room');
131139
}
132140

141+
await produceUpdateHistory(roomId, userId, HistoryStatus.FORFEITED);
133142
const allUsersForfeited = updatedRoom.users.every(user => user.isForfeit === true);
134143
if (allUsersForfeited) {
135144
const result = await closeRoomById(roomId);

services/collaboration/src/events/consumer.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { Queues } from './queues';
22
import messageBroker from './broker';
33
import { createRoomWithQuestion } from '../controllers/roomController';
44
import { QuestionFoundEvent } from '../types/event';
5-
import { produceCollabCreated, produceCollabCreateFailedEvent } from './producer';
5+
import { produceCollabCreated, produceCollabCreateFailedEvent, produceCreateHistory } from './producer';
66

77
async function consumeQuestionFound(message: QuestionFoundEvent) {
88
console.log('Attempting to create room:', message);
@@ -15,6 +15,12 @@ async function consumeQuestionFound(message: QuestionFoundEvent) {
1515
if (roomId) {
1616
console.log('Room created with ID:', message, roomId);
1717
await produceCollabCreated(requestId1, requestId2, roomId, question);
18+
await produceCreateHistory(
19+
roomId,
20+
{ _id: user1.id, username: user1.username },
21+
{ _id: user2.id, username: user2.username },
22+
question,
23+
);
1824
} else {
1925
console.log('Failed to create room:', message);
2026
await produceCollabCreateFailedEvent(requestId1, requestId2);

services/collaboration/src/events/producer.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { CollabCreatedEvent, IdType, MatchFailedEvent, Question } from '../types/event';
2+
import { CreateHistoryMessage, HistoryStatus, UpdateHistoryMessage, User } from '../types/message';
23
import messageBroker from './broker';
34
import { Queues } from './queues';
45

@@ -18,3 +19,13 @@ export async function produceCollabCreateFailedEvent(requestId1: IdType, request
1819
const message: MatchFailedEvent = { requestId1, requestId2, reason: COLLAB_CREATED_ERROR };
1920
await messageBroker.produce(Queues.MATCH_FAILED, message);
2021
}
22+
23+
export async function produceCreateHistory(roomId: IdType, user1: User, user2: User, question: Question) {
24+
const message: CreateHistoryMessage = { roomId, user1, user2, question };
25+
await messageBroker.produce(Queues.CREATE_HISTORY, message);
26+
}
27+
28+
export async function produceUpdateHistory(roomId: IdType, userId: IdType, status: HistoryStatus) {
29+
const message: UpdateHistoryMessage = { roomId, userId, status };
30+
await messageBroker.produce(Queues.UPDATE_HISTORY, message);
31+
}

services/collaboration/src/events/queues.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,6 @@ export enum Queues {
66
QUESTION_FOUND = 'QUESTION_FOUND',
77
COLLAB_CREATED = 'COLLAB_CREATED',
88
MATCH_FAILED = 'MATCH_FAILED',
9+
CREATE_HISTORY = 'CREATE_HISTORY',
10+
UPDATE_HISTORY = 'UPDATE_HISTORY',
911
}

0 commit comments

Comments
 (0)