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

grpc-health-check: Version 2.0 #2575

Merged
merged 2 commits into from
Sep 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 18 additions & 16 deletions packages/grpc-health-check/README.md
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Original file: proto/health/v1/health.proto


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

export interface HealthCheckRequest__Output {
'service': (string);
}
Original file line number Diff line number Diff line change
@@ -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);
}
Loading
Loading