terminus
terminus copied to clipboard
Example code for gRPC healthcheck does not work
Is there an existing issue for this?
- [X] I have searched the existing issues
Current behavior
Code from examples/grpc does not work as expected returning status 500 and message 'null', while console prints out the Exception Error that it cannot connect to all connections.
Minimum reproduction code
Code from examples/grpc
Steps to reproduce
- copy code from exaples/grpc
- access route to trigger a health controller
- See error in browser/Postman and error in the console.
Expected behavior
It should correctly connect to the microservice and return the actual state of that microservice. The client folder of examples/grpc is missing the part about registering proto for this certain health check. I have found a solution so I can create a pull request with missing part.
Package version
7.2.0
NestJS version
7.6.18
Node.js version
14.17.0
In which operating systems have you tested?
- [X] macOS
- [ ] Windows
- [ ] Linux
Other
I can prepare a pull request with required changes so that the example code could work as expected.
Hi @Baroshem, you mean the one in the sample/004-grpc-app?
Hi @Tony133
Yes exactly, I copy pasted the code from the example and it was not able to connect to the microservice and return its state. What I have found was missing in my case were the options for grpcHealthIndicator with transport and proto declaration. When I added these options to my healthcheck service it was returning corectly.
So basically what I think is missing from the example is similar code that you have in the server folder but for client.
{
transport: Transport.GRPC,
options: {
package: 'grpc.health.v1',
protoPath: join(__dirname, '../protos/health.proto'),
},
}
This part is added to the server but not to the client so I think that client cannot connect to grpc microservice because of that. At least adding this to the client worked for my case.
I can create a pull request with my changes so that it will be easier to see.
I tried the example (sample/004-grpc-app) and it returned an empty object, so there is something wrong, I used version 8 of NestJS, as the examples are all updated to the latest version.
What kind of error does he give?
However, if you want to contribute, feel free to pull for this problem. 👍
@Tony133
I checked it once again. It does indeed work in your example but it does not work if you are using microservices and trying to connect to check the state of the microservice.
So in my case what I needed to add was something like this:
check() {
return this.health.check([
async () =>
this.grpc.checkService<GrpcOptions>('hero_service', 'grpc.health.v1', {
timeout: 2000,
package: 'grpc.health.v1',
url: 'localhost:3001'
protoPath: [join(__dirname, '../../protos/health.proto')],
}),
]);
}
Without it, I was not able to connect to the microservice and return the appriopriate state. Let me know if you would like me to add this to the example. I tested it and it does not break the current test (if I add this part) and can help people who are struggling with microservices just like me :)
Hi @Baroshem,
I did this, taking an example from what you said.
in src/client/health/health.controller.ts in I did it like this:
//src/client/health/health.controller.ts
import { Controller, Get } from '@nestjs/common';
import { GrpcOptions } from '@nestjs/microservices';
import { join } from 'path';
import {
HealthCheck,
HealthCheckService,
GRPCHealthIndicator,
} from '@nestjs/terminus';
@Controller('health')
export class HealthController {
constructor(
private health: HealthCheckService,
private grpc: GRPCHealthIndicator,
) {}
@Get()
@HealthCheck()
check() {
return this.health.check([
async () =>
this.grpc.checkService<GrpcOptions>('hero_service', 'grpc.health.v1', {
timeout: 2000,
package: 'grpc.health.v1',
url: 'localhost:3001',
protoPath: join(__dirname, '../../protos/health.proto'),
}),
]);
}
}
while in src/server/main.ts in I did it like this:
//src/server/main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { join } from 'path';
import { Transport } from '@nestjs/microservices';
async function bootstrap() {
const app = await NestFactory.createMicroservice(AppModule, {
transport: Transport.GRPC,
options: {
package: 'grpc.health.v1',
url: 'localhost:3001',
protoPath: join(__dirname, '../protos/health.proto'),
},
});
app.listen();
console.log('Microservice is listening');
}
bootstrap();
from browser or curl, it gives me this(see screenshot):
gives you the same json back to you too?
@Tony133
Yes but only when I wrap health controller with try catch and return value like this
try {
const check = await this.healthService.check();
res.send(check?.details);
} catch (error) {
res.status(error?.status).send(error?.response?.details);
}
If I won't do that it will then return empty page in the browser but request will return correct data.
@Baroshem strange as i explained above to me it works, but are you using version 7.x or version 8.x of NestJS?
@Baroshem I tried deleting the node_modules folder and reinstalling everything and now it works with the same code that is inside samples/004-grpc-app. Very strange
However if you find some time create a minimal reproduction in a clonable git repository in order to better evaluate the problem.
@Baroshem Thanks for pointing out those extra options to insert that were missing in the sample.
For me it works the same way as @Tony133 shows, without the need to wrap with try, catch
Edit: NestJS v8
Somewhat related question. What about microservices that don't open a TCP port by default, like Kafka? Is it possible to make terminus write to /tmp so we could do health check with exec for example?
https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#define-readiness-probes
I've been given the task to write a healthcheck with terminus. We have a hybrid app that has grpc. This stuff really confuses me. What is the 'hero_service' and how do you know it is OK?