Can't publish to rabbitmq from NestJS - rabbitmq

I had a working code before refactoring, but cannot seem to find the issue now. I am getting no errors, but my consumer is not receiving, neither does the rabbitmq management show a 2nd connection.
Module
#Module({
imports: [
TypeOrmModule.forFeature([User]),
forwardRef(() => ActionModule),
TypeFormModule,
ClientsModule.register([
{
name: 'MATCHING_SERVICE',
transport: Transport.RMQ,
options: {
urls: ['amqp://localhost:5672'],
queue: 'matching',
queueOptions: {
durable: true,
},
},
},
]),
],
providers: [UsersService],
exports: [UsersService],
controllers: [UsersController],
})
Service
constructor(
#Inject('MATCHING_SERVICE') private client: ClientProxy,
) {}
Function
async test() {
const message = await this.client.send({ cmd: 'greeting-async' }, 'Progressive Coder');
return message;
}

Related

Nest.js RabbitMQ not sending/receiving message

I have two microservices with Nest.js both of them connected to RabbitMQ service (one is the publisher and one is the receiver)
From the publisher I am trying to send a message to the receiver and seems that its not doing anything at all
Publisher :
auth.module.ts :
imports:[ClientsModule.registerAsync([
{
name: 'RMQ_SERVICE',
imports: [ConfigModule],
useFactory: (configService: ConfigService) => ({
transport: Transport.RMQ,
options: {
urls: [`amqp://${configService.get('RMQ_HOST')}:5672`],
queue: 'api-queue',
queueOptions: {
durable: false,
},
},
}),
inject: [ConfigService],
},
]),
]
auth.service.ts :
#Inject('RMQ_SERVICE') private readonly client: ClientProxy,
and using it like that :
this.client.send({ cmd: 'create-user-data' },{});
Receiver :
main.ts :
app.connectMicroservice<MicroserviceOptions>({
transport: Transport.RMQ,
options: {
noAck: false,
urls: [`amqp://${process.env.RMQ_HOST}:5672`],
queue: 'api-queue',
queueOptions: {
durable: false,
},
},
});
await app.startAllMicroservices();
users-data.controler.ts :
#MessagePattern({ cmd: 'create-user-data'})
async createUserData() {
console.log('create-user-data');
}
cant see any errors also i have rabbitmq web monitor and cannot see there any messages
any idea what wrong ?
if ill use emit and EventPattern its working i dont understand why ?
ok so after long digging i just needed to do
const result = await this.client.send(
{ cmd: 'create-user-data' },
{
userId: user.id,
provider,
...socialUser,
},
);
await result.subscribe();
and i received the message on the receiver

How to test email sending with Mailhog on local?

Setup mailhog with docker-compose like:
version: '3'
services:
mailhog:
image: mailhog/mailhog
ports:
- 8025:8025
- 1025:1025
It's possible to access localhost:8025 from browser. Maybe the SMTP server 1025 also works but don't know how to confirm it.
In a NestJS application, for testing the email code as:
#Module({
imports: [NodeMailerModule],
providers: [MailHogEmailRepository],
exports: [MailHogEmailRepository],
})
class MailHogEmailRepositoryModule {}
#Module({
imports: [MailHogEmailRepositoryModule],
providers: [
{
provide: EmailRepository,
useFactory: (
config: ConfigService,
mailHog: MailHogEmailRepository,
) => {
return mailHog;
}
},
inject: [ConfigService, MailHogEmailRepository],
},
],
exports: [EmailRepository],
})
export class EmailRepositoryModule {}
MailHogEmailRepository send with nodemailer:
#Injectable()
export class MailHogEmailRepository implements EmailRepository {
constructor(
#Inject(NodeMailerToken) private readonly nodemailer: Transporter,
) {}
async send(email: Email) {
const options = {
to: email.to,
from: email.from,
subject: email.subject,
};
await this.nodemailer.sendMail(options);
}
}
nodemailer config:
import { Module } from '#nestjs/common';
import { ConfigService } from '#nestjs/config';
import { createTransport } from 'nodemailer';
export const NodeMailerToken = Symbol('nodemailer');
#Module({
providers: [
{
provide: NodeMailerToken,
useFactory: (config: ConfigService) =>
createTransport({
host: 'localhost',
port: 1025,
secure: true,
}),
inject: [ConfigService],
},
],
exports: [NodeMailerToken],
})
export class NodeMailerModule {}
In test source, it always timeout:
import { Test, TestingModule } from '#nestjs/testing';
import request from 'supertest';
import {
FastifyAdapter,
NestFastifyApplication,
} from '#nestjs/platform-fastify';
describe('Test sender', () => {
let app: NestFastifyApplication;
beforeEach(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [AppModule],
}).compile();
app = moduleFixture.createNestApplication(new FastifyAdapter());
await app.init();
await app.getHttpAdapter().getInstance().ready();
});
describe('/handler (POST)', () => {
describe('should send data to mail server', () => {
it('success', () => {
const message = ...
return request(app.getHttpServer())
.post('/handler')
.send({ message })
.expect(200);
});
});
});
});
$ npm run test
thrown: "Exceeded timeout of xxx ms for a test.
Use jest.setTimeout(newTimeout) to increase the timeout value, if this is a long-running test."
It seems the test case couldn't access the mailhog server running in docker container. How to set it correctly?

Cannot connect NestJS Bull to Elasticache (Redis)

I stuck when connecting NestJS Bull to AWS Elasticache on deployment
On local I easily connect to Redis by
import { Module } from '#nestjs/common';
import { BullModule } from '#nestjs/bull';
#Module({
imports: [
BullModule.forRoot({
redis: {
host: 'localhost',
port: 6379,
password: 'secret',
},
}),
],
})
export class AppModule {}
I even try on https://app.redislabs.com/ a official Redis cloud. It still working.
But on deployment with Elasticache. There is no error on startup but the queue is not worked as expected
My code last year was worked, But now no response
import Redis from 'ioredis';
#Module({
imports: [
BullModule.forRoot({
createClient: () => {
return config.get('redis.cluster.host')
? new Redis.Cluster([
{
port: +config.get('redis.cluster.port'),
host: config.get('redis.cluster.host'),
},
])
: new Redis(+config.get('redis.standalone.port'), config.get('redis.standalone.host'));
},
}),
FeeQueue,
],
providers: [],
exports: [],
})
export class QueuesModule {}
Could you have time to help me. Thanks
I don't know if it'll be the same for you, but I just ran into a similar issue. The queue wasn't working, but no error logged. After a lot of testing, I finally got it to log an error saying that enableReadyCheck and maxRetriesPerRequest can't be used for bclients and subscibers. So I unset them:
BullModule.forRoot({
createClient: (type) => {
const opts =
type !== 'client'
? { enableReadyCheck: false, maxRetriesPerRequest: null }
: {}
return config.get('redis.cluster.host')
? new Redis.Cluster([{ host, port }], opts)
: new Redis({ host, port, ...opts});
},
})

Adding serialport and usb in NestJS?

Is it possible to add a serial port and USB package in NestJS? I can't seem to find anything regarding these things.
In your serial.module.ts, create your custom serial handler service by custom factory providers
import { SerialHandlerService } from './serial-handler.service';
#Module({
providers: [
{
provide: 'SerialHandlerService',
useFactory: SerialHandlerService,
},
],
})
export class SerialModule {}
Create serial-handler.service.ts in same folder
import * as SerialPort from 'serialport';
const Readline = SerialPort.parsers.Readline;
export const SerialHandlerService = () => {
const port = new SerialPort(
{YOUR_SERIAL_PORT},
{
baudRate: {YOUR_SERIAL_BOADRATE},
dataBits: {YOUR_SERIAL_DATABITS},
stopBits: {YOUR_SERIAL_STOPBITS},
parity: {YOUR_SERIAL_PARITY},
},
(err) => {
if (err) {
console.error(err)
// Handle Error
}
console.log('success')
},
);
// I'm using Readline parser here. But, You can change parser that you want!
const parser = new Readline({ delimiter: '\r\n' });
port.pipe(parser);
port.on('open', () => {
console.info('port opened');
});
parser.on('data', (data) => {
console.log(data);
// Data is string, process your data below!
}
}
Add your serial.module.ts in your app.module.ts
#Module({
imports: [
// your other modules...
SerialModule,
],
controllers: [],
providers: [],
})
export class AppModule {}
[Reference: https://docs.nestjs.com/fundamentals/custom-providers#factory-providers-usefactory]

How to configure middleware in e2e test in nestjs

In real app, we write:
export class AppModule implements NestModule {
constructor() {}
configure(consumer: MiddlewareConsumer) {
consumer.apply(JwtExtractionMiddleware).forRoutes({
path: 'graphql',
method: RequestMethod.ALL,
});
}
}
In e2e test, I do something like this:
const module = await Test.createTestingModule({
imports: [ GraphQLModule.forRoot(e2eGqlConfig) ],
providers: [ PubUserResolver ],
}).compile();
app = await module.createNestApplication().init();
So how can I specific middleware in e2e test?
Maybe try to create a specific TestModule class only for e2e and provide it to the createTestingModule?
#Module({
imports: [ GraphQLModule.forRoot(e2eGqlConfig) ],
providers: [ PubUserResolver ],
})
export class TestModule implements NestModule {
constructor() {}
configure(consumer: MiddlewareConsumer) {
consumer.apply(JwtExtractionMiddleware).forRoutes({
path: 'graphql',
method: RequestMethod.ALL,
});
}
}
And then in e2e:
const module = await Test.createTestingModule({
imports: [TestModule]
}).compile();
app = await module.createNestApplication().init();
I had similar problem, I needed to attach global middlewares. There is no info on the Internet about that as well, but by chance I've found the solution. Maybe someone will be looking for it, so here it is:
To use global middleware in e2e in NestJS:
Firstly create the app, but don't init it. Only compile:
const app = Test
.createTestingModule({ imports: [AppModule] })
.compile()
.createNestApplication();
After that you can add all your global middlewares:
app.enableCors();
app.use(json());
app.use(formDataMiddleware(config));
Now init the app and that's it:
await app.init();
You'll need to put app.use(new AuthMiddleware().use); before app.init().
describe('Module E2E', () => {
const mockedTest = {
create: jest.fn().mockImplementation((t) => Promise.resolve(t)),
};
let app: INestApplication;
beforeAll(async () => {
const moduleRef = await Test.createTestingModule({
imports: [
ConfigModule.forRoot({
load: [configuration],
}),
],
controllers: [TestController],
providers: [
TestService, // the service contains a MySQL Model
{
provide: getModelToken(Test), // Test is the name of Model
useValue: mockedTest,
},
],
}).compile();
app = moduleRef.createNestApplication();
app.use(new AuthMiddleware().use); // auth middleware
await app.init();
});
});