Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HealthCheck reports SERVING even when it is defined as NOT_SERVING #27839

Closed
DanielDagnino opened this issue Oct 27, 2021 · 3 comments
Closed

Comments

@DanielDagnino
Copy link

DanielDagnino commented Oct 27, 2021

I am trying to create a server with two services and a HealthCheck in each one, so I can check them independently and use reflection to know the methods exposed in each one. I have hardcoded one service as NOT_SERVING to test it, however, for some reason, it is not working. I would appreciate some help.

I have created a short script to reproduce this result.

The proto file definition:

syntax = "proto3";

package test;

service Greeter {
    rpc SayHello (HelloRequest) returns (HelloReply) {}
}

message HelloRequest {
    string name = 1;
}

message HelloReply {
    string message = 1;
}

service Byeer {
    rpc SayBye (ByeRequest) returns (ByeReply) {}
}

message ByeRequest {
    string name = 1;
}

message ByeReply {
    string message = 1;
}

The Python server:

from concurrent import futures
import grpc
from grpc_health.v1 import health, health_pb2, health_pb2_grpc
from grpc_reflection.v1alpha import reflection
import test_pb2_grpc
import test_pb2


class Greeter(test_pb2_grpc.GreeterServicer):

    def SayHello(self, request, context):
        return test_pb2.HelloReply(message='Hello, %s!' % request.name)

    def Check(self, request, context):
        return health_pb2.HealthCheckResponse(status=health_pb2.HealthCheckResponse.SERVING)

    def Watch(self, request, context):
        return health_pb2.HealthCheckResponse(status=health_pb2.HealthCheckResponse.UNIMPLEMENTED)


class Byeer(test_pb2_grpc.ByeerServicer):

    def SayBye(self, request, context):
        return test_pb2.HelloReply(message='Bye, %s!' % request.name)

    def Check(self, request, context):
        return health_pb2.HealthCheckResponse(status=health_pb2.HealthCheckResponse.NOT_SERVING)

    def Watch(self, request, context):
        return health_pb2.HealthCheckResponse(status=health_pb2.HealthCheckResponse.UNIMPLEMENTED)


def run_server():
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=None))
    server.add_insecure_port('[::]:8000')

    test_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server)
    health_pb2_grpc.add_HealthServicer_to_server(Greeter(), server)

    test_pb2_grpc.add_ByeerServicer_to_server(Byeer(), server)
    health_pb2_grpc.add_HealthServicer_to_server(Byeer(), server)

    services = tuple(service.full_name for service in health_pb2.DESCRIPTOR.services_by_name.values())
    services += tuple(service.full_name for service in test_pb2.DESCRIPTOR.services_by_name.values())
    services += (reflection.SERVICE_NAME,)
    reflection.enable_server_reflection(services, server)

    server.start()
    server.wait_for_termination()


if __name__ == "__main__":
    run_server()

When I test the reflection and the server methods, it works:

grpcurl -plaintext localhost:8000 list
grpcurl -plaintext localhost:8000 list test.Byeer
grpcurl -plaintext localhost:8000 list test.Greeter
grpcurl --plaintext -d '{"name": "John Doe"}' localhost:8000 test.Greeter/SayHello
grpcurl --plaintext -d '{"name": "John Doe"}' localhost:8000 test.Byeer/SayBye

The reflections report the proper methods and the server the correct response.

The HealthCheck on the server and the Greeter service work too:

grpcurl --plaintext -d '' localhost:8000 grpc.health.v1.Health/Check
grpcurl --plaintext -d '{"service": "test.Greeter"}' localhost:8000 grpc.health.v1.Health/Check

So, it reports SERVING as expected.

However, the HealthCheck on the Byeer service, and whatever other name I use, also reports SERVING:

grpcurl --plaintext -d '{"service": "test.Byeer"}' localhost:8000 grpc.health.v1.Health/Check
grpcurl --plaintext -d '{"service": "xxx"}' localhost:8000 grpc.health.v1.Health/Check

And I would expect NOT_SERVING.

Any idea?
Thanks in advance.

@yashykt
Copy link
Member

yashykt commented Nov 2, 2021

Please forums such as grpcio google group or stack overflow for questions like these so that the wider community might be able to help. I'm gonna go ahead and close this but I'll tag @lidizheng and @gnossen for a post-close answer.

@yashykt yashykt closed this as completed Nov 2, 2021
@lidizheng
Copy link
Contributor

@DanielDagnino

The Health Checking service sets health status per service name: https://grpc.github.io/grpc/python/grpc_health_checking.html

from grpc_health.v1 import health, health_pb2, health_pb2_grpc

health_servicer = HealthServicer()
# You can set the health status upfront or dynamically in other parts of the application
health_servicer.set("helloworld.Greeter", health_pb2.HealthCheckResponse.NOT_SERVING)
server = ...
health_pb2_grpc.add_HealthServicer_to_server(health_servicer, server)

The full service name is proto package name + the service name, you can find it in the generated code (example).

@DanielDagnino
Copy link
Author

Thanks! I also asked in StackOverflow. The solution to the problem is in here:
https://stackoverflow.com/questions/69751113/grpc-healthcheck-reports-serving-even-when-it-is-defined-as-not-serving

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants