NestJS - Microservices - Kafka Exception Handling - node.js

I'm using NestJS to implement a microservice architecture, I'm using CLIENT app using NestJS,
The client app receives a rest request and sends to Kafka to get the result
try {
const pattern = 'findDoctors';
const payload = body;
const doctors = await lastValueFrom(
this.client.send(pattern, payload).pipe(timeout(50000)),
);
return doctors;
} catch (e) {
console.log(e);
throw new Error(e);
}
And in the microservice side (Hybrid Application for now, will remove the rest apis later)
#MessagePattern('findDoctors')
findDoctors(#Payload() message): any {
return this.doctorService.searchForDoctors(message.value);
}
async searchForDoctors(data): Promise<any[]> {
this.logger.info('Started search for doctors job');
throw 'Not Found';
}
After i throw the exception i get in the logs
node:17720) UnhandledPromiseRejectionWarning: TypeError [ERR_INVALID_ARG_TYPE]: The first argument must be of type string or an instance of Buffer, ArrayBuffer, or Array or an Array-like Object. Received an instance of Object
at Function.from (buffer.js:330:9)
at ServerKafka.assignErrorHeader (C:\Users\Desktop\Projects\node_modules\#nestjs\microservices\server\server-kafka.js:137:73)
at ServerKafka.sendMessage (C:\Users\Desktop\Projects\node_modules\#nestjs\microservices\server\server-kafka.js:119:14)
at C:\Users\Desktop\Projects\node_modules\#nestjs\microservices\server\server-kafka.js:81:31
at C:\Users\Desktop\node_modules\#nestjs\microservices\server\server.js:46:31
at processTicksAndRejections (internal/process/task_queues.js:79:11)
(node:17720) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 3)
(node:17720) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
and the client side just waits to timeout and never receive an exception response from the micro service
Tried using RpcException but it's the same

Found the answer
used
return new RpcException('not found');
instead of
throw new RpcException('not found')
throwing the exception needs an exception filter to catch it
#Catch(RpcException)
export class ExceptionFilter implements RpcExceptionFilter<RpcException> {
catch(exception: RpcException, host: ArgumentsHost): Observable<any> {
return throwError(exception.getError());
}
}
and in the client side you can catch the error when using filters and return a normal http exception, or use filters on that too
#Post('/search')
async findAll(#Body() body) {
console.log('Sending kafka msg');
try {
const doctors = await this.doctorService.findDoctors(body);
return doctors;
} catch (e) {
console.log(e)
throw new HttpException({
status: '500',
error: e.message,
}, 500)
}
}

Related

Unhandled Promise Rejection Warning Occured

I want to create Product Categories , so i handle it in productController class database call in productCatService class. I added JS promise to this . now it gives following error.
productCatController.js
module.exports.createProductCat = async (request, response)=> {
let result = await productCatService.createProductCat(productCatData);
if (result) {
responseService.successWithData(response, "Product Category Created");
} else {
responseService.errorWithMessage(response, result);
}
}
productCatService.js
module.exports.createProductCat = (productCatData) => {
let productCat = {
name: productCatData.name,
desc: productCatData.desc,
count:productCatData.count,
status : productCatData.status
};
return new Promise((resolve,reject)=>{
ProductCategory.create(productCat).then(result => {
resolve(true);
}).catch(error => {
reject(false)
})
});
}
Error
(node:18808) UnhandledPromiseRejectionWarning: false
(Use `node --trace-warnings ...` to show where the warning was created)
(node:18808) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a p
romise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.
html#cli_unhandled_rejections_mode). (rejection id: 2)
(node:18808) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a no
n-zero exit code.
Never use await without try/catch. You don't have to try/catch every await, but somewhere down the call stack there needs to be a try/catch block.
You don't need try/catch here, just return the promise from ProductCategory.create()...
// productCatService.js
module.exports.createProductCat = (productCatData) => ProductCategory.create({
name: productCatData.name,
desc: productCatData.desc,
count: productCatData.count,
status: productCatData.status
});
...but you definitely need try/catch here, as this function is the bottom of the stack for this operation, and it is responsible for signifying overall success or failure to the caller.
// productCatController.js
module.exports.createProductCat = async (request, response) => {
try {
await productCatService.createProductCat(productCatData);
responseService.successWithData(response, "Product Category Created");
} catch (err) {
responseService.errorWithMessage(response, err);
}
}
Also don't use new Promise() for operations that already are promises. Keep using the promise you already have. Wrapping new Promise() around existing promises is a source of useless bloat, and it can introduce subtle bugs. Avoid.

nodejs unhandled promise rejection when app.post

When my angular frontend sends post request
order(market: string, price: string, side: string, size: string): Observable<any> {
var payload = { market: market, order: { price: price, side: side, size: size } };
return this.http.post<any>('http://localhost:3000' + "/orders", payload))
.pipe(
tap((res: any) => {
console.log(res);
}),
retry(3), // retry a failed request up to 3 times
catchError(this.handleError) // then handle the error
);
}
my nodejs server receives it
app.post('/orders', (req, res) => {
console.log(req.body)
// more code
setTimeout(function () {
axios.post('https://test.com/api/orders', payload, { headers: headers })
.then((response) => {
if (response.status === 201) {
res.sendStatus(201);
} else {
res.sendStatus(400);
}
})
}, 500);
});
I added setTimeout because without it I'm getting Error: Request failed with status code 400.
As a result, I can post an order to test.com/api/orders, but getting promise rejection.
(node:9220) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag --unhandled-rejections=strict (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 2)
(node:9220) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
Any enhancement i can make here?
Try moving the function content into a try block and catch the errors.
I also recommend to use async await keywords.

Unit Testing HTTP Post request with database access

Hi I'm currently trying to learn and implement some unit testing for my HTTP Requests. currently I have a SQlite db setup, and a simple post request. This is the test I have written so far:
"use strict";
process.env.NODE_ENV = 'test';
const chai = require('chai');
const chaiHttp = require('chai-http');
chai.use(chaiHttp);
const expect = chai.expect;
const app = require('../../../app');
chai.request('http://localhost:8080')
.put('/tempValue')
.send({sensorid: '1', sensorValue: '25.00', timeRecorded: '2020-04-12 12:30'})
.then(function (res) {
expect(res).to.have.status(200);
})
.catch(function (err) {
throw err;
});
I seem to be getting a error that it is unable to open the database file. Currently I am just connecting to the database in the app.js file, using const dbPath = "./database/database.db"; and const dbConnection = sqlite.open(dbPath, { Promise });
I also seem to get errors about incorrect use of .catch? This is the error log:
(node:13952) UnhandledPromiseRejectionWarning: Error: SQLITE_CANTOPEN: unable to open database file
(node:13952) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unha
ndled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:13952) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
(node:13952) UnhandledPromiseRejectionWarning: AssertionError: expected { Object (_events, _eventsCount, ...) } to have status code 200 but got 404
at D:\Uni Work\3rd Year\302CEM - Agile Development\Penguin Project\test\api\temperature\get.js:15:29
at processTicksAndRejections (internal/process/task_queues.js:97:5)
(node:13952) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unha
ndled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 2)
Thanks for any help!
EDIT:
This is the particular post request I'm testing, it uses MQTT to check if the message being sent is to that topic structure, then inserts into the database.
app.ws.use(route.all('/tempValue', function (ctx){
client.on('message', async function(topic,message){
console.log(topic, message.toString());
if (topic === '302CEM/Penguin/Room1/Temperature'){
const SQL = "INSERT INTO sensorData (sensorid, sensorValue, timeRecorded) VALUES (?,?,?)";
try {
const temptostring = message.toString();
const db = await dbConnection;
await db.run(SQL, ["1",temptostring, moment().format('YYYY-MM-DD HH:mm')]);
ctx.websocket.send(temptostring);
} catch (err) {
console.log(err);
}
}
})
}));

Retrieving JSON data from an Axios response

I'm using TypeScript to create a Node.js application and I want to retrieve JSON data from an external API. I have a demo version of the code I'm using, can't put my actual codebase up.
private async getData() {
return await Axios.get(
`http://dummy.restapiexample.com/api/v1/employees`
).then(response => {
return response.data;
});
}
getReleaseResults() {
this.getData().then(responseData => {
responseData.data.data.forEach((element: any) => {
console.log(element);
});
});
}
The error message I get is: (node:6068) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'forEach' of undefined
at C:\Users\Caoilinn.Hughes\OneDrive\Documents\TypeScript Demos\Azure Test Result Email Extension\emailAzureExtension\app\out\js\apiCaller.js:43:36
at processTicksAndRejections (internal/process/task_queues.js:97:5)
(node:6068) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag --unhandled-rejections=strict (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:6068) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
If I don't have the for each and replace it with
console.log(responseData.data.data)
I don't get any issues. FYI the result set has a data property hence the "data.data"
The problem is that you are already returning response.data from your get function and then again you are doing data.data which would not work.
see this. Remove extra data.
getReleaseResults() {
this.getData().then(responseData => {
responseData.data.forEach((element: any) => {
console.log(element);
});
});
}
Add catch block to get the error if there is any. What is the expected response ? try to log it.
return await Axios.get(
`http://dummy.restapiexample.com/api/v1/employees`
).then(response => {
console.log(response);
return response.data;
}).catch(err => console.log(err));

proxyReq.setHeader can not set headers after they are sent

i am building a node.js proxy and i want to add a conditional header
proxy.on('proxyReq', (proxyReq, req, res) => {
const realIP = parseHttpHeader(req.headers['x-real-ip'])[0];
const path = parseHttpHeader(req.headers['x-original-uri'])[0];
pAny([
check_ip(realIP) ,
check_path(path) ,
check_geo(realIP)
]).then(result => {
console.log (result , "result " )
if (result) {
proxyReq.setHeader('namespace' , 'foo');
} else {
proxyReq.setHeader('namespace' , 'bar'); }
console.log('sending req ')
});
});
.
async function check_ip(realIP) {
try {
const result = await ipModel.findOne({ip: realIP}).exec()
console.log(realIP , result , "ip")
if (result) {
return true
} else {
return false
}
} catch (e) {
throw e;
}
}
and it works just fine till i use the methos check_ip then i get the error
(node:3793) UnhandledPromiseRejectionWarning: Error: Can't set headers after they are sent.
at validateHeader (_http_outgoing.js:491:11)
at ClientRequest.setHeader (_http_outgoing.js:498:3)
at /home/master/IPS/server.js:109:14
at <anonymous>
at process._tickCallback (internal/process/next_tick.js:189:7)
(node:3793) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:3793) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
as the error clearly states i am handeling a promise in the wrong way but i don't know how to fix it i tried using callbacks i tried using await
make the check_ip return a promise and try
function check_ip(realIP) {
return ipModel.findOne({ ip: realIP }).exec();
}

Resources