Skip to content

Commit 812b62a

Browse files
authored
Merge pull request #14 from 7codeRO/feature/add-sqs-and-kafka-modules
Added SqsModule and KafkaModule as showcase
2 parents 029efe9 + be1dcfc commit 812b62a

8 files changed

+2280
-13
lines changed

package-lock.json

Lines changed: 2131 additions & 13 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
"prisma:seed": "ts-node prisma/seed.ts"
2222
},
2323
"dependencies": {
24+
"@aws-sdk/client-sqs": "^3.454.0",
2425
"@nestjs/common": "^9.3.9",
2526
"@nestjs/config": "^2.3.1",
2627
"@nestjs/core": "^9.3.9",
@@ -35,6 +36,7 @@
3536
"cors": "^2.8.5",
3637
"crypto": "^1.0.1",
3738
"dotenv": "^8.2.0",
39+
"kafkajs": "^2.2.4",
3840
"passport": "^0.4.1",
3941
"passport-jwt": "^4.0.0",
4042
"reflect-metadata": "^0.1.13",
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { Injectable, OnApplicationShutdown } from '@nestjs/common';
2+
import {
3+
Consumer,
4+
ConsumerRunConfig,
5+
ConsumerSubscribeTopics,
6+
Kafka,
7+
} from 'kafkajs';
8+
9+
@Injectable()
10+
export class ConsumerService implements OnApplicationShutdown {
11+
private readonly kafka = new Kafka({
12+
brokers: ['localhost:9092'],
13+
});
14+
15+
private readonly consumers: Consumer[] = [];
16+
17+
async consume(topic: ConsumerSubscribeTopics, config: ConsumerRunConfig) {
18+
const consumer = this.kafka.consumer({ groupId: 'nestjs-kafka' });
19+
await consumer.connect();
20+
await consumer.subscribe(topic);
21+
await consumer.run(config);
22+
this.consumers.push(consumer);
23+
}
24+
25+
async onApplicationShutdown(signal?: string) {
26+
for (const consumer of this.consumers) {
27+
await consumer.disconnect();
28+
}
29+
}
30+
}

src/modules/kafka/kafka.module.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { Module } from '@nestjs/common';
2+
import { ProducerService } from './kafka.producer.service';
3+
import { ConsumerService } from './kafka.consumer.service';
4+
5+
@Module({
6+
providers: [ProducerService, ConsumerService],
7+
exports: [ProducerService, ConsumerService],
8+
})
9+
export class KafkaModule {}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import {
2+
Injectable,
3+
OnApplicationShutdown,
4+
OnModuleInit,
5+
} from '@nestjs/common';
6+
import { Kafka } from 'kafkajs';
7+
8+
@Injectable()
9+
export class ProducerService implements OnModuleInit, OnApplicationShutdown {
10+
private readonly kafka = new Kafka({
11+
brokers: ['localhost:9092'],
12+
});
13+
14+
private readonly producer = this.kafka.producer();
15+
16+
async onModuleInit() {
17+
await this.producer.connect();
18+
}
19+
20+
async produce(record: any) {
21+
await this.producer.send(record);
22+
}
23+
24+
async onApplicationShutdown(signal?: string) {
25+
await this.producer.disconnect();
26+
}
27+
}

src/modules/sqs/sqs.controller.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { Controller, Get } from '@nestjs/common';
2+
import { SQSService } from './sqs.service';
3+
4+
@Controller()
5+
export class SqsController {
6+
constructor(private readonly sqsService: SQSService) {}
7+
}

src/modules/sqs/sqs.module.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { Logger, Module } from '@nestjs/common';
2+
import { SQSService } from './sqs.service';
3+
import { SqsController } from './sqs.controller';
4+
5+
@Module({
6+
imports: [],
7+
controllers: [SqsController],
8+
providers: [SQSService, Logger],
9+
exports: [SQSService],
10+
})
11+
export class SqsModule {}

src/modules/sqs/sqs.service.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import { Injectable, Logger } from '@nestjs/common';
2+
import {
3+
DeleteMessageCommand,
4+
ReceiveMessageCommand,
5+
SQSClient,
6+
} from '@aws-sdk/client-sqs';
7+
8+
@Injectable()
9+
export class SQSService {
10+
private readonly logger = new Logger(SQSService.name);
11+
private sqs: SQSClient;
12+
private indexingJobProgressQueue = 'queue_url';
13+
14+
constructor() {
15+
this.sqs = new SQSClient({
16+
region: 'us-east-1',
17+
});
18+
}
19+
20+
public async deleteMessage(message) {
21+
const deleteParams = {
22+
QueueUrl: this.indexingJobProgressQueue,
23+
ReceiptHandle: message.ReceiptHandle,
24+
};
25+
26+
const deleteCommand = new DeleteMessageCommand(deleteParams);
27+
try {
28+
await this.sqs.send(deleteCommand);
29+
this.logger.log('Message deleted successfully.');
30+
} catch (err) {
31+
this.logger.error('Error deleting message:', err);
32+
}
33+
}
34+
35+
public async receiveMessages(callback) {
36+
const params = {
37+
QueueUrl: this.indexingJobProgressQueue,
38+
// MaxNumberOfMessages: 5, // Maximum number of messages to receive (1-10)
39+
WaitTimeSeconds: 1, // maximum 20 seconds
40+
};
41+
42+
const receiveCommand = new ReceiveMessageCommand(params);
43+
44+
try {
45+
const response = await this.sqs.send(receiveCommand);
46+
const messages = response.Messages || [];
47+
48+
if (messages.length === 0) {
49+
this.logger.log('No messages received.');
50+
return;
51+
}
52+
53+
messages.forEach((message) => {
54+
this.logger.log('Received message:', message.Body);
55+
callback(message);
56+
});
57+
} catch (err) {
58+
this.logger.error('Error receiving messages:', err);
59+
} finally {
60+
await this.receiveMessages(callback);
61+
}
62+
}
63+
}

0 commit comments

Comments
 (0)