Skip to content

Commit

Permalink
Merge pull request #2575 from murgatroid99/health-check_2.0
Browse files Browse the repository at this point in the history
grpc-health-check: Version 2.0
  • Loading branch information
murgatroid99 committed Sep 25, 2023
2 parents 32c816c + 524bb7d commit 71936fa
Show file tree
Hide file tree
Showing 18 changed files with 858 additions and 192 deletions.
34 changes: 18 additions & 16 deletions packages/grpc-health-check/README.md
Expand Up @@ -4,11 +4,7 @@ Health check client and service for use with gRPC-node.

## Background

This package exports both a client and server that adhere to the [gRPC Health Checking Protocol](https://github.com/grpc/grpc/blob/master/doc/health-checking.md).

By using this package, clients and servers can rely on common proto and service definitions. This means:
- Clients can use the generated stubs to health check _any_ server that adheres to the protocol.
- Servers do not reimplement common logic for publishing health statuses.
This package provides an implementation of the [gRPC Health Checking Protocol](https://github.com/grpc/grpc/blob/master/doc/health-checking.md) service, as described in [gRFC L106](https://github.com/grpc/proposal/blob/master/L106-node-heath-check-library.md).

## Installation

Expand All @@ -22,33 +18,39 @@ npm install grpc-health-check

### Server

Any gRPC-node server can use `grpc-health-check` to adhere to the gRPC Health Checking Protocol.
Any gRPC-node server can use `grpc-health-check` to adhere to the gRPC Health Checking Protocol.
The following shows how this package can be added to a pre-existing gRPC server.

```javascript 1.8
```typescript
// Import package
let health = require('grpc-health-check');
import { HealthImplementation, ServingStatusMap } from 'grpc-health-check';

// Define service status map. Key is the service name, value is the corresponding status.
// By convention, the empty string "" key represents that status of the entire server.
// By convention, the empty string '' key represents that status of the entire server.
const statusMap = {
"ServiceFoo": proto.grpc.health.v1.HealthCheckResponse.ServingStatus.SERVING,
"ServiceBar": proto.grpc.health.v1.HealthCheckResponse.ServingStatus.NOT_SERVING,
"": proto.grpc.health.v1.HealthCheckResponse.ServingStatus.NOT_SERVING,
'ServiceFoo': 'SERVING',
'ServiceBar': 'NOT_SERVING',
'': 'NOT_SERVING',
};

// Construct the service implementation
let healthImpl = new health.Implementation(statusMap);
const healthImpl = new HealthImplementation(statusMap);

healthImpl.addToServer(server);

// Add the service and implementation to your pre-existing gRPC-node server
server.addService(health.service, healthImpl);
// When ServiceBar comes up
healthImpl.setStatus('serviceBar', 'SERVING');
```

Congrats! Your server now allows any client to run a health check against it.

### Client

Any gRPC-node client can use `grpc-health-check` to run health checks against other servers that follow the protocol.
Any gRPC-node client can use the `service` object exported by `grpc-health-check` to generate clients that can make health check requests.

### Command Line Usage

The absolute path to `health.proto` can be obtained on the command line with `node -p 'require("grpc-health-check").protoPath'`.

## Contributing

Expand Down
28 changes: 19 additions & 9 deletions packages/grpc-health-check/gulpfile.ts
Expand Up @@ -19,22 +19,32 @@ import * as gulp from 'gulp';
import * as mocha from 'gulp-mocha';
import * as execa from 'execa';
import * as path from 'path';
import * as del from 'del';
import {linkSync} from '../../util';

const healthCheckDir = __dirname;
const baseDir = path.resolve(healthCheckDir, '..', '..');
const testDir = path.resolve(healthCheckDir, 'test');
const outDir = path.resolve(healthCheckDir, 'build');

const runInstall = () => execa('npm', ['install', '--unsafe-perm'], {cwd: healthCheckDir, stdio: 'inherit'});
const execNpmVerb = (verb: string, ...args: string[]) =>
execa('npm', [verb, ...args], {cwd: healthCheckDir, stdio: 'inherit'});
const execNpmCommand = execNpmVerb.bind(null, 'run');

const runRebuild = () => execa('npm', ['rebuild', '--unsafe-perm'], {cwd: healthCheckDir, stdio: 'inherit'});
const install = () => execNpmVerb('install', '--unsafe-perm');

const install = gulp.series(runInstall, runRebuild);
/**
* Transpiles TypeScript files in src/ to JavaScript according to the settings
* found in tsconfig.json.
*/
const compile = () => execNpmCommand('compile');

const runTests = () => {
return gulp.src(`${outDir}/test/**/*.js`)
.pipe(mocha({reporter: 'mocha-jenkins-reporter',
require: ['ts-node/register']}));
};

const test = () => gulp.src(`${testDir}/*.js`).pipe(mocha({reporter: 'mocha-jenkins-reporter'}));
const test = gulp.series(install, runTests);

export {
install,
compile,
test
}
}
55 changes: 0 additions & 55 deletions packages/grpc-health-check/health.js

This file was deleted.

27 changes: 18 additions & 9 deletions packages/grpc-health-check/package.json
@@ -1,6 +1,6 @@
{
"name": "grpc-health-check",
"version": "1.8.0",
"version": "2.0.0",
"author": "Google Inc.",
"description": "Health check client and service for use with gRPC-node",
"repository": {
Expand All @@ -14,18 +14,27 @@
"email": "mlumish@google.com"
}
],
"scripts": {
"compile": "tsc -p .",
"prepare": "npm run generate-types && npm run compile",
"generate-types": "proto-loader-gen-types --keepCase --longs String --enums String --defaults --oneofs --includeComments --includeDirs proto/ -O src/generated health/v1/health.proto",
"generate-test-types": "proto-loader-gen-types --keepCase --longs String --enums String --defaults --oneofs --includeComments --includeDirs proto/ -O test/generated --grpcLib=@grpc/grpc-js health/v1/health.proto"
},
"dependencies": {
"google-protobuf": "^3.4.0",
"grpc": "^1.6.0",
"lodash.clone": "^4.5.0",
"lodash.get": "^4.4.2"
"@grpc/proto-loader": "^0.7.10",
"typescript": "^5.2.2"
},
"files": [
"LICENSE",
"README.md",
"health.js",
"v1"
"src",
"build",
"proto"
],
"main": "health.js",
"license": "Apache-2.0"
"main": "build/src/health.js",
"types": "build/src/health.d.ts",
"license": "Apache-2.0",
"devDependencies": {
"@grpc/grpc-js": "file:../grpc-js"
}
}
73 changes: 73 additions & 0 deletions packages/grpc-health-check/proto/health/v1/health.proto
@@ -0,0 +1,73 @@
// Copyright 2015 The gRPC Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// The canonical version of this proto can be found at
// https://github.com/grpc/grpc-proto/blob/master/grpc/health/v1/health.proto

syntax = "proto3";

package grpc.health.v1;

option csharp_namespace = "Grpc.Health.V1";
option go_package = "google.golang.org/grpc/health/grpc_health_v1";
option java_multiple_files = true;
option java_outer_classname = "HealthProto";
option java_package = "io.grpc.health.v1";

message HealthCheckRequest {
string service = 1;
}

message HealthCheckResponse {
enum ServingStatus {
UNKNOWN = 0;
SERVING = 1;
NOT_SERVING = 2;
SERVICE_UNKNOWN = 3; // Used only by the Watch method.
}
ServingStatus status = 1;
}

// Health is gRPC's mechanism for checking whether a server is able to handle
// RPCs. Its semantics are documented in
// https://github.com/grpc/grpc/blob/master/doc/health-checking.md.
service Health {
// Check gets the health of the specified service. If the requested service
// is unknown, the call will fail with status NOT_FOUND. If the caller does
// not specify a service name, the server should respond with its overall
// health status.
//
// Clients should set a deadline when calling Check, and can declare the
// server unhealthy if they do not receive a timely response.
//
// Check implementations should be idempotent and side effect free.
rpc Check(HealthCheckRequest) returns (HealthCheckResponse);

// Performs a watch for the serving status of the requested service.
// The server will immediately send back a message indicating the current
// serving status. It will then subsequently send a new message whenever
// the service's serving status changes.
//
// If the requested service is unknown when the call is received, the
// server will send a message setting the serving status to
// SERVICE_UNKNOWN but will *not* terminate the call. If at some
// future point, the serving status of the service becomes known, the
// server will send a new message with the service's serving status.
//
// If the call terminates with status UNIMPLEMENTED, then clients
// should assume this method is not supported and should not retry the
// call. If the call terminates with any other status (including OK),
// clients should retry the call with appropriate exponential backoff.
rpc Watch(HealthCheckRequest) returns (stream HealthCheckResponse);
}
10 changes: 10 additions & 0 deletions packages/grpc-health-check/src/generated/grpc/health/v1/Health.ts
@@ -0,0 +1,10 @@
// Original file: proto/health/v1/health.proto

import type { MethodDefinition } from '@grpc/proto-loader'
import type { HealthCheckRequest as _grpc_health_v1_HealthCheckRequest, HealthCheckRequest__Output as _grpc_health_v1_HealthCheckRequest__Output } from '../../../grpc/health/v1/HealthCheckRequest';
import type { HealthCheckResponse as _grpc_health_v1_HealthCheckResponse, HealthCheckResponse__Output as _grpc_health_v1_HealthCheckResponse__Output } from '../../../grpc/health/v1/HealthCheckResponse';

export interface HealthDefinition {
Check: MethodDefinition<_grpc_health_v1_HealthCheckRequest, _grpc_health_v1_HealthCheckResponse, _grpc_health_v1_HealthCheckRequest__Output, _grpc_health_v1_HealthCheckResponse__Output>
Watch: MethodDefinition<_grpc_health_v1_HealthCheckRequest, _grpc_health_v1_HealthCheckResponse, _grpc_health_v1_HealthCheckRequest__Output, _grpc_health_v1_HealthCheckResponse__Output>
}
@@ -0,0 +1,10 @@
// Original file: proto/health/v1/health.proto


export interface HealthCheckRequest {
'service'?: (string);
}

export interface HealthCheckRequest__Output {
'service': (string);
}
@@ -0,0 +1,37 @@
// Original file: proto/health/v1/health.proto


// Original file: proto/health/v1/health.proto

export const _grpc_health_v1_HealthCheckResponse_ServingStatus = {
UNKNOWN: 'UNKNOWN',
SERVING: 'SERVING',
NOT_SERVING: 'NOT_SERVING',
/**
* Used only by the Watch method.
*/
SERVICE_UNKNOWN: 'SERVICE_UNKNOWN',
} as const;

export type _grpc_health_v1_HealthCheckResponse_ServingStatus =
| 'UNKNOWN'
| 0
| 'SERVING'
| 1
| 'NOT_SERVING'
| 2
/**
* Used only by the Watch method.
*/
| 'SERVICE_UNKNOWN'
| 3

export type _grpc_health_v1_HealthCheckResponse_ServingStatus__Output = typeof _grpc_health_v1_HealthCheckResponse_ServingStatus[keyof typeof _grpc_health_v1_HealthCheckResponse_ServingStatus]

export interface HealthCheckResponse {
'status'?: (_grpc_health_v1_HealthCheckResponse_ServingStatus);
}

export interface HealthCheckResponse__Output {
'status': (_grpc_health_v1_HealthCheckResponse_ServingStatus__Output);
}

0 comments on commit 71936fa

Please sign in to comment.