How can handle RabbitMQ consumer timeout in NestJS - rabbitmq

I'm using RabbitMQ as message broker between my Rest API GW and microservices.
{
provide: 'MY-MICROSERVICE',
useFactory: (configService: ConfigService) => {
const user = configService.get('RABBITMQ_USER');
const password = configService.get('RABBITMQ_PASSWORD');
const host = configService.get('RABBITMQ_HOST');
const queue = configService.get('RABBITMQ_MY_QUEUE');
return ClientProxyFactory.create({
transport: Transport.RMQ,
options: {
urls: [`amqp://${user}:${password}#${host}`],
queue,
queueOptions: {
durable: true,
},
noAck: true,
},
});
},
inject: [ConfigService],
},
When using req/response method MessagePattern, I need to set a timeout If the consumer not being available for any reason.
Is it possible?
Currently, my REST endpoint getting Timed out, and all things getting queued, and when a consumer gets back to work it processes all of them.

Related

NestJS backend as a microservice and an API Rest the same time?

Can a NestJS backend be a microservice and an API Rest as the same time ?
main.ts for a microservice:
const microservice = await NestFactory.createMicroservice<MicroserviceOptions>(
AppModule,
{
transport: Transport.KAFKA,
// ...options, client, consumer, etc...
},
);
await microservice.listen();
main.ts for a REST API:
const app = await NestFactory.create(AppModule)
await app.listen(3000);
How to mix use create and createMicroservice in the same main.ts ?
Should I use a Gateway API with the serviceA as microservice and serviceB as REST API ?
Pretty sure what you're looking for is a hybrid application. You create the regular HTTP application with NestFactory.create() and then you use app.connectMicroservice() to add microservices that should run alongside the HTTP server.
Example from the docs:
const app = await NestFactory.create(AppModule);
// microservice #1
const microserviceTcp = app.connectMicroservice<MicroserviceOptions>({
transport: Transport.TCP,
options: {
port: 3001,
},
});
// microservice #2
const microserviceRedis = app.connectMicroservice<MicroserviceOptions>({
transport: Transport.REDIS,
options: {
host: 'localhost',
port: 6379,
},
});
await app.startAllMicroservices();
await app.listen(3001);

Nestjs rabbitmq publisher, consumer and hhtp API in one application

I need to know if it's possible to have all these three in single application. I have seen many examples where there are two different project one for RabbitMQ publisher and one for subscriber/consumer.
I just need to know if there's a possibility to implement something like that. I failed to find any example consisting both in one app.
I have tried to implement something similar but it did not work.
folder structure :
src
--main.ts
--app.service.ts
--app.resolver.ts
--app.module.ts
main.ts file
async function bootstrap() {
let RUNPORT = process.env.PORT ? process.env.PORT : 3000;
const app = await NestFactory.create<NestExpressApplication>(AppModule);
app.connectMicroservice<MicroserviceOptions>({
transport: Transport.RMQ,
options: {
urls: [`amqp://guest:guest#localhost:5672`],
queue: 'email-subscribers',
queueOptions: {
durable: true,
},
noAck: false,
// Get one by one
prefetchCount: 1,
},
});
app.startAllMicroservices();
await app.listen(3000);
}
bootstrap();
app.module.ts file
providers: [
AppService,
AppResolver,
{
provide: 'GREETING_SERVICE',
useFactory: (configService: ConfigService) => {
const user = configService.get('RABBITMQ_USER');
const password = configService.get('RABBITMQ_PASSWORD');
const host = configService.get('RABBITMQ_HOST');
const queueName = configService.get('RABBITMQ_QUEUE_NAME');
return ClientProxyFactory.create({
transport: Transport.RMQ,
options: {
urls: [`amqp://${user}:${password}#${host}`],
queue: queueName,
queueOptions: {
durable: true,
},
},
});
},
inject: [ConfigService],
},
],
app.resolver.ts
#Resolver()
export class AppResolver {
constructor(
private readonly appService: AppService,
#Inject('GREETING_SERVICE') private client: ClientProxy,
) {}
#Public()
#Query(() => String)
async getHello() {
// this.client.emit('new_message', { text: 'Myu data' });
this.client.send('new_message', 'boom baby').subscribe();
return await this.appService.getHello();
}
#EventPattern('new_message')
async getDataPublish(data) {
console.log(data);
// return this.appService.publishEvent(data);
}

Send message from service to other components (React Native)

I'm thinking about the best way how to implement rabbitmq or mqtt sending messages from callback(queue.on) to chat component and last dialogs component, where I will update dialogs and chats. I heard about eventemitter, but I don't know best way,try to use eventemitter or make own handlers. I am very new in react.
MessageBrokerService:
import {Connection, Exchange, Queue} from "react-native-rabbitmq";
import uuid from 'react-native-uuid';
export default class RabbitMQService {
startEventSubscribe = (exchange) => {
exchangeName = exchange;
connection.connect();
}
}
const config = {
host: '',
port: 5671,
username: '',
password: '',
virtualhost: '/',
ttl: 10000,
ssl: true,
};
let connection = new Connection(config);
let queue;
let exchangeName;
connection.on('connected', event => {
queue = new Queue(
connection,
{
name: uuid.v4(),
durable: true,
},
{
// queueDeclare args here like x-message-ttl
},
);
let exchange = new Exchange(connection, {
name: exchangeName,
});
queue.bind(exchange, '');
// Receive messages
queue.on('message', message => {
console.log(message);
**I want from here send messages to chat component and last dialogs from here**
queue.basicAck(message.delivery_tag);
});
});
connection.on('error', event => {
console.log('fail');
console.log(event);
});
const publishMessage = message => {
let routing_key = 'message-exchange';
let properties = {
//header authorization jwt
};
let exchangeSendMessages = new Exchange(connection, {
name: 'message-exchange',
type: 'direct',
durable: true,
});
exchangeSendMessages.publish(message, routing_key, properties);
};
Last Dialogs screen:
const LastDialogsScreen = () => {
**Want here to receive messages here from callback in MessageBrokerService**
return ()
}
Chat screen:
const ChatScreen = () => {
**Want here to receive messages in here too from callback in MessageBrokerService**
return ()
}

Change rabbitmq exchange with nestjs

I am using rabbitmq with nestjs. I need to replicate a message from one queue to another. I set up an exchange on rabbitmq to make it work. But how can I change the exchange of rabbitmq inside nestjs?
my api gateway
my current rabbitmq configuration inside nestjs:
constructor( ) {
this.rabbitmq = ClientProxyFactory.create({
transport: Transport.RMQ,
options: {
urls: [`amqp://${this.configService.get<string>('RABBITMQ_USER')}:${this.configService.get<string>('RABBITMQ_PASSWORD')}#${this.configService.get<string>('RABBITMQ_URL')}`],
queue: 'students'
}
})
}
createStudent(#Body() body: CreateStudentDto): Observable<any> {
return this.rabbitmq.send('createStudent', body)
}
my client
#MessagePattern('createStudent')
async createStudent(#Payload() student: Student, #Ctx() context: RmqContext) {
const channel = context.getChannelRef()
const originalMsg = context.getMessage()
try {
let response = await this.studentService.createStudent(student)
await channel.ack(originalMsg)
return response;
} catch(error) {
this.logger.log(`error: ${JSON.stringify(error.message)}`)
const filterAckError = ackErrors.filter(ackError => error.message.includes(ackError))
if (filterAckError.length > 0) {
await channel.ack(originalMsg)
}
}
}
I need the message to be sent to two queues.

Unable to authenticate a user using #hapi/cookie 19.x.x

I've recently upgraded my project to use hapi 19.x.x along with that I have updated the project to use #hapi/cookie as opposed to the deprecated hap-auth-cookie however after successful authentication my application constantly tries to reauthenticate even after setting a session cookie with request.cookieAuth.set({ id : id})
When the application is redirected to the 'restricted page' using the redirectTo: property on the .auth.strategy('admin', 'cookie', {}) object.
I noticed that the state on the incoming request is {} empty when it shouldn't be
node -v // 12.16.2
Google Chrome
Version 80.0.3987.163 (Official Build) (64-bit)
package.json {
"dependencies": {
"#hapi/catbox-redis": "5.0.5",
"#hapi/cookie": "11.0.1",
"#hapi/h2o2": "9.0.1",
"#hapi/hapi": "19.1.1",
"#hapi/inert": "6.0.1",
"#hapi/joi": "17.1.1",
"#hapi/scooter": "6.0.0",
"#hapi/wreck": "17.0.0",
}
server.auth.strategy('admin', 'cookie', {
cookie: {
name: Server.cookieName,
password: auth_cookie_password,
isSecure: false,
ttl: Server.cacheCookieTtlMs
},
appendNext: true,
redirectTo: outboundUrl,
validateFunc: async (request: any, session: any) => {
// blah blah
}
{
method: ['GET', 'POST'],
path: '/login',
options: {
auth: false,
security: true
},
handler: async (request: any, h) => {
try {
const tokenSet = await authCallback();
const session = {
id: tokenSet.id,
}
request.cookieAuth.set(session);
const returnScript = `<script type="application/javascript" >(function() { setTimeout(function() {window.location = "http://localhost:3000"})})()</script>`;
return h.response(returnScript)
} catch (e) {
return h.response('Internal server error').code(500)
}
}
}
any help would be appreciated.
you have to set the cookie path to /
Cookies are only sent to the server when the URL of the request starts with the value of the cookie’s path. When you omit path, the default is the URL of the request that received the response with the Set-Cookie header. So, let’s say you omit path and your cookie is set on a URL like https://example.com/login (which is very common), then the cookie will only be sent on requests for subpaths like https://example.com/login/foo, which is almost never what you want.