Cannot connect NestJS Bull to Elasticache (Redis) - 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});
},
})

Related

Can't publish to rabbitmq from NestJS

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;
}

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

Serving app with Client-Side Routing in NestJs

I have a sample react app using react-router-dom with one route "/reset/:token"
when I run my app in development server and navigate to my route everything works fine
but in server static using ServeStaticModule when I navigate to my route I get "Cannot GET /reset/5T4665" and 404
status code
Here is my code:
App.module
#Module({
imports: [
ConfigModule.forRoot({
envFilePath: 'config/' + `.${process.env.NODE_ENV}.env`,
isGlobal: true,
}),
MongooseModule.forRoot(`${process.env.MONGO_URI}`),
ServeStaticModule.forRoot({
rootPath: join(__dirname, '..', 'public'),
renderPath: '/',
}),
BullModule.forRoot({
redis: {
host: 'localhost',
port: 6379,
},
}),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
Any helps would be appreciated
I fix it by adding Asterisk in field renderPath
ServeStaticModule.forRoot({
rootPath: join(__dirname, '..', 'public'),
renderPath: '/*',
}),
Source : https://create-react-app.dev/docs/deployment/#serving-apps-with-client-side-routing

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?

#golevelup/nestjs-rabbitmq CircleCI issue, timed out

I am creating a microservice in NestJS. Now I want to use RabbitMQ to send messages to another service.
I created the functionality and it works perfectly fine. But the problem comes up when I want to merge it and the CircleCI test is running. After 10 minutes I get the message:
Too long with no output (exceeded 10m0s): context deadline exceeded
This happens only on the service with the producer. The consuming service works fine.
Can someone explain why this happens and how I can fix this?
RabbitMQ is imported in the GraphQLModule below.
#Module({
imports: [
GraphQLFederationModule.forRoot({
autoSchemaFile: true,
context: ({ req }) => ({ req }),
}),
DatabaseModule,
AuthModule,
RabbitmqModule,
],
providers: [UserResolver, FamilyResolver, AuthResolver],
})
export class GraphQLModule {}
RabbitmqModule:
import { Global, Module } from '#nestjs/common';
import { ConfigService } from '#nestjs/config';
import { RabbitMQModule } from '#golevelup/nestjs-rabbitmq';
import { UserProducer } from './producers/user.producer';
#Global()
#Module({
imports: [
RabbitMQModule.forRootAsync(RabbitMQModule, {
useFactory: async (config: ConfigService) => ({
exchanges: [
{
name: config.get('rabbitMQ.exchange'),
type: config.get('rabbitMQ.exchangeType'),
},
],
uri: config.get('rabbitMQ.url'),
connectionInitOptions: { wait: false },
}),
inject: [ConfigService],
}),
],
providers: [UserProducer],
exports: [UserProducer],
})
export class RabbitmqModule {}
The CircleCI output:
UPDATE:
It crashes when it starts seeding the database. It seeds the database correctly but when it is done, it doesn't stop the app. This happens on my PC too, not only in CircleCi.
The following script is called:
import { NestFactory } from '#nestjs/core';
import { SeedService } from '../src/database/service/seed.service';
import { AppModule } from '../src/app/app.module';
async function bootstrap() {
const app = await NestFactory.createApplicationContext(AppModule);
try {
await app.get(SeedService).seed();
} catch (error) {
throw error;
} finally {
await app.close();
}
}
bootstrap();
But this doesn't close the app correctly. When I log before and after await app.close() it logs both.
It's hard to tell without knowing a little bit more about your scenario. What is it that the task in Circle CI is trying to accomplish? From the screenshot it looks like you may be attempting to use this script to apply database migrations?
If you boot up the entire microservice like this it's going to hold the process open waiting for potential messages to come through. Are you calling app.close() anywhere in your script? You will need to terminate the process appropriately once your script is completed or refactor this to not require booting up the whole service like this