@loopback/health 0.8.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +25 -0
- package/README.md +135 -0
- package/dist/controllers/health.controller.d.ts +10 -0
- package/dist/controllers/health.controller.js +158 -0
- package/dist/controllers/health.controller.js.map +1 -0
- package/dist/controllers/index.d.ts +1 -0
- package/dist/controllers/index.js +9 -0
- package/dist/controllers/index.js.map +1 -0
- package/dist/health.component.d.ts +9 -0
- package/dist/health.component.js +44 -0
- package/dist/health.component.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/keys.d.ts +25 -0
- package/dist/keys.js +32 -0
- package/dist/keys.js.map +1 -0
- package/dist/observers/health.observer.d.ts +14 -0
- package/dist/observers/health.observer.js +72 -0
- package/dist/observers/health.observer.js.map +1 -0
- package/dist/observers/index.d.ts +1 -0
- package/dist/observers/index.js +9 -0
- package/dist/observers/index.js.map +1 -0
- package/dist/types.d.ts +23 -0
- package/dist/types.js +14 -0
- package/dist/types.js.map +1 -0
- package/package.json +57 -0
- package/src/controllers/health.controller.ts +157 -0
- package/src/controllers/index.ts +6 -0
- package/src/health.component.ts +50 -0
- package/src/index.ts +15 -0
- package/src/keys.ts +39 -0
- package/src/observers/health.observer.ts +88 -0
- package/src/observers/index.ts +6 -0
- package/src/types.ts +37 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
Copyright (c) IBM Corp. 2019.
|
|
2
|
+
Node module: @loopback/health
|
|
3
|
+
This project is licensed under the MIT License, full text below.
|
|
4
|
+
|
|
5
|
+
--------
|
|
6
|
+
|
|
7
|
+
MIT license
|
|
8
|
+
|
|
9
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
10
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
11
|
+
in the Software without restriction, including without limitation the rights
|
|
12
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
13
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
14
|
+
furnished to do so, subject to the following conditions:
|
|
15
|
+
|
|
16
|
+
The above copyright notice and this permission notice shall be included in
|
|
17
|
+
all copies or substantial portions of the Software.
|
|
18
|
+
|
|
19
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
20
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
21
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
22
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
23
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
24
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
25
|
+
THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# @loopback/health
|
|
2
|
+
|
|
3
|
+
This module contains a component to report health status using
|
|
4
|
+
[@cloudnative/health](https://github.com/CloudNativeJS/cloud-health).
|
|
5
|
+
|
|
6
|
+
## Installation
|
|
7
|
+
|
|
8
|
+
```sh
|
|
9
|
+
npm install --save @loopback/health
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Basic use
|
|
13
|
+
|
|
14
|
+
The component should be loaded in the constructor of your custom Application
|
|
15
|
+
class.
|
|
16
|
+
|
|
17
|
+
Start by importing the component class:
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
import {HealthComponent} from '@loopback/health';
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
In the constructor, add the component to your application:
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
this.component(HealthComponent);
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
By default, three routes are exposed at:
|
|
30
|
+
|
|
31
|
+
- `/health` - overall health status
|
|
32
|
+
- `/live` - liveness status
|
|
33
|
+
- `/ready` - readiness status
|
|
34
|
+
|
|
35
|
+
The paths can be customized via Health configuration as follows:
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
this.configure(HealthBindings.COMPONENT).to({
|
|
39
|
+
healthPath: '/health',
|
|
40
|
+
livePath: '/live',
|
|
41
|
+
readyPath: '/ready',
|
|
42
|
+
});
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
{% include note.html content="*this.configure()* must be called before
|
|
46
|
+
*this.component()* to take effect. This is a
|
|
47
|
+
[known limitation](https://github.com/loopbackio/loopback-next/issues/4289#issuecomment-564617263)
|
|
48
|
+
." %}
|
|
49
|
+
|
|
50
|
+
http://localhost:3000/health returns health in JSON format, such as:
|
|
51
|
+
|
|
52
|
+
```json
|
|
53
|
+
{
|
|
54
|
+
"status": "UP",
|
|
55
|
+
"checks": [
|
|
56
|
+
{"name": "readiness", "state": "UP", "data": {"reason": ""}},
|
|
57
|
+
{"name": "liveness", "state": "UP", "data": {"reason": ""}}
|
|
58
|
+
]
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
It also has to be noted, that by default the OpenAPI spec is disabled and
|
|
63
|
+
therefore the endpoints will not be visible in the API explorer. The spec can be
|
|
64
|
+
enabled by setting `openApiSpec` to `true`.
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
this.configure(HealthBindings.COMPONENT).to({
|
|
68
|
+
openApiSpec: true,
|
|
69
|
+
});
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Add custom `live` and `ready` checks
|
|
73
|
+
|
|
74
|
+
The health component allows extra
|
|
75
|
+
[`live` and `ready` checks](https://github.com/CloudNativeJS/cloud-health#readiness-vs-liveness)
|
|
76
|
+
to be added.
|
|
77
|
+
|
|
78
|
+
_Liveness probes_ are used to know when to restart a container. For example, in
|
|
79
|
+
case of a deadlock due to a multi-threading defect which might not crash the
|
|
80
|
+
container but keep the application unresponsive. A custom liveness probe would
|
|
81
|
+
detect this failure and restart the container.
|
|
82
|
+
|
|
83
|
+
_Readiness probes_ are used to decide when the container is available for
|
|
84
|
+
accepting traffic. It is important to note, that readiness probes are
|
|
85
|
+
periodically checked and not only at startup.
|
|
86
|
+
|
|
87
|
+
**Important:** It is recommended to avoid checking dependencies in liveness
|
|
88
|
+
probes. Liveness probes should be inexpensive and have response times with
|
|
89
|
+
minimal variance.
|
|
90
|
+
|
|
91
|
+
```ts
|
|
92
|
+
import {LiveCheck, ReadyCheck, HealthTags} from '@loopback/health';
|
|
93
|
+
|
|
94
|
+
const myLiveCheck: LiveCheck = () => {
|
|
95
|
+
return Promise.resolve();
|
|
96
|
+
};
|
|
97
|
+
app.bind('health.MyLiveCheck').to(myLiveCheck).tag(HealthTags.LIVE_CHECK);
|
|
98
|
+
|
|
99
|
+
// Define a provider to check the health of a datasource
|
|
100
|
+
class DBHealthCheckProvider implements Provider<ReadyCheck> {
|
|
101
|
+
constructor(@inject('datasources.db') private ds: DataSource) {}
|
|
102
|
+
|
|
103
|
+
value() {
|
|
104
|
+
return () => this.ds.ping();
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
app
|
|
109
|
+
.bind('health.MyDBCheck')
|
|
110
|
+
.toProvider(DBHealthCheckProvider)
|
|
111
|
+
.tag(HealthTags.READY_CHECK);
|
|
112
|
+
|
|
113
|
+
const myReadyCheck: ReadyCheck = () => {
|
|
114
|
+
return Promise.resolve();
|
|
115
|
+
};
|
|
116
|
+
app.bind('health.MyReadyCheck').to(myReadyCheck).tag(HealthTags.READY_CHECK);
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Contributions
|
|
120
|
+
|
|
121
|
+
- [Guidelines](https://github.com/loopbackio/loopback-next/blob/master/docs/CONTRIBUTING.md)
|
|
122
|
+
- [Join the team](https://github.com/loopbackio/loopback-next/issues/110)
|
|
123
|
+
|
|
124
|
+
## Tests
|
|
125
|
+
|
|
126
|
+
Run `npm test` from the root folder.
|
|
127
|
+
|
|
128
|
+
## Contributors
|
|
129
|
+
|
|
130
|
+
See
|
|
131
|
+
[all contributors](https://github.com/loopbackio/loopback-next/graphs/contributors).
|
|
132
|
+
|
|
133
|
+
## License
|
|
134
|
+
|
|
135
|
+
MIT
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Constructor } from '@loopback/core';
|
|
2
|
+
import { HealthOptions } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* A factory function to create a controller class for health endpoints. This
|
|
5
|
+
* makes it possible to customize decorations such as `@get` with a dynamic
|
|
6
|
+
* path value not known at compile time.
|
|
7
|
+
*
|
|
8
|
+
* @param options - Options for health endpoints
|
|
9
|
+
*/
|
|
10
|
+
export declare function createHealthController(options?: HealthOptions): Constructor<unknown>;
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright IBM Corp. 2019. All Rights Reserved.
|
|
3
|
+
// Node module: @loopback/health
|
|
4
|
+
// This file is licensed under the MIT License.
|
|
5
|
+
// License text available at https://opensource.org/licenses/MIT
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.createHealthController = void 0;
|
|
8
|
+
const tslib_1 = require("tslib");
|
|
9
|
+
const health_1 = require("@cloudnative/health");
|
|
10
|
+
const core_1 = require("@loopback/core");
|
|
11
|
+
const rest_1 = require("@loopback/rest");
|
|
12
|
+
const keys_1 = require("../keys");
|
|
13
|
+
const types_1 = require("../types");
|
|
14
|
+
function getHealthResponseObject() {
|
|
15
|
+
/**
|
|
16
|
+
* OpenAPI definition of health response schema
|
|
17
|
+
*/
|
|
18
|
+
const HEALTH_RESPONSE_SCHEMA = {
|
|
19
|
+
type: 'object',
|
|
20
|
+
properties: {
|
|
21
|
+
status: { type: 'string' },
|
|
22
|
+
checks: {
|
|
23
|
+
type: 'array',
|
|
24
|
+
items: {
|
|
25
|
+
type: 'object',
|
|
26
|
+
properties: {
|
|
27
|
+
name: { type: 'string' },
|
|
28
|
+
state: { type: 'string' },
|
|
29
|
+
data: {
|
|
30
|
+
type: 'object',
|
|
31
|
+
properties: {
|
|
32
|
+
reason: { type: 'string' },
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* OpenAPI definition of health response
|
|
42
|
+
*/
|
|
43
|
+
const HEALTH_RESPONSE = {
|
|
44
|
+
description: 'Health Response',
|
|
45
|
+
content: {
|
|
46
|
+
'application/json': {
|
|
47
|
+
schema: HEALTH_RESPONSE_SCHEMA,
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
return HEALTH_RESPONSE;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* OpenAPI spec for health endpoints
|
|
55
|
+
*/
|
|
56
|
+
const HEALTH_SPEC = {
|
|
57
|
+
// response object needs to be cloned because the oas-validator throws an
|
|
58
|
+
// error if the same object is referenced twice
|
|
59
|
+
responses: {
|
|
60
|
+
'200': getHealthResponseObject(),
|
|
61
|
+
'500': getHealthResponseObject(),
|
|
62
|
+
'503': getHealthResponseObject(),
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* OpenAPI spec to hide endpoints
|
|
67
|
+
*/
|
|
68
|
+
const HIDDEN_SPEC = {
|
|
69
|
+
responses: {},
|
|
70
|
+
'x-visibility': 'undocumented',
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* A factory function to create a controller class for health endpoints. This
|
|
74
|
+
* makes it possible to customize decorations such as `@get` with a dynamic
|
|
75
|
+
* path value not known at compile time.
|
|
76
|
+
*
|
|
77
|
+
* @param options - Options for health endpoints
|
|
78
|
+
*/
|
|
79
|
+
function createHealthController(options = types_1.DEFAULT_HEALTH_OPTIONS) {
|
|
80
|
+
const spec = options.openApiSpec ? HEALTH_SPEC : HIDDEN_SPEC;
|
|
81
|
+
/**
|
|
82
|
+
* Controller for health endpoints
|
|
83
|
+
*/
|
|
84
|
+
let HealthController = class HealthController {
|
|
85
|
+
constructor(healthChecker) {
|
|
86
|
+
this.healthChecker = healthChecker;
|
|
87
|
+
}
|
|
88
|
+
async health(response) {
|
|
89
|
+
const status = await this.healthChecker.getStatus();
|
|
90
|
+
return handleStatus(response, status);
|
|
91
|
+
}
|
|
92
|
+
async ready(response) {
|
|
93
|
+
const status = await this.healthChecker.getReadinessStatus();
|
|
94
|
+
return handleStatus(response, status, 503);
|
|
95
|
+
}
|
|
96
|
+
async live(response) {
|
|
97
|
+
const status = await this.healthChecker.getLivenessStatus();
|
|
98
|
+
return handleStatus(response, status, 500);
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
tslib_1.__decorate([
|
|
102
|
+
rest_1.get(options.healthPath, spec),
|
|
103
|
+
tslib_1.__param(0, core_1.inject(rest_1.RestBindings.Http.RESPONSE)),
|
|
104
|
+
tslib_1.__metadata("design:type", Function),
|
|
105
|
+
tslib_1.__metadata("design:paramtypes", [Object]),
|
|
106
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
107
|
+
], HealthController.prototype, "health", null);
|
|
108
|
+
tslib_1.__decorate([
|
|
109
|
+
rest_1.get(options.readyPath, spec),
|
|
110
|
+
tslib_1.__param(0, core_1.inject(rest_1.RestBindings.Http.RESPONSE)),
|
|
111
|
+
tslib_1.__metadata("design:type", Function),
|
|
112
|
+
tslib_1.__metadata("design:paramtypes", [Object]),
|
|
113
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
114
|
+
], HealthController.prototype, "ready", null);
|
|
115
|
+
tslib_1.__decorate([
|
|
116
|
+
rest_1.get(options.livePath, spec),
|
|
117
|
+
tslib_1.__param(0, core_1.inject(rest_1.RestBindings.Http.RESPONSE)),
|
|
118
|
+
tslib_1.__metadata("design:type", Function),
|
|
119
|
+
tslib_1.__metadata("design:paramtypes", [Object]),
|
|
120
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
121
|
+
], HealthController.prototype, "live", null);
|
|
122
|
+
HealthController = tslib_1.__decorate([
|
|
123
|
+
core_1.injectable({ scope: core_1.BindingScope.SINGLETON }),
|
|
124
|
+
tslib_1.__param(0, core_1.inject(keys_1.HealthBindings.HEALTH_CHECKER)),
|
|
125
|
+
tslib_1.__metadata("design:paramtypes", [health_1.HealthChecker])
|
|
126
|
+
], HealthController);
|
|
127
|
+
return HealthController;
|
|
128
|
+
}
|
|
129
|
+
exports.createHealthController = createHealthController;
|
|
130
|
+
/**
|
|
131
|
+
* Create response for the given status
|
|
132
|
+
* @param response - Http response
|
|
133
|
+
* @param status - Health status
|
|
134
|
+
* @param failingCode - Status code for `DOWN`
|
|
135
|
+
*/
|
|
136
|
+
function handleStatus(response, status, failingCode = 503) {
|
|
137
|
+
let statusCode = 200;
|
|
138
|
+
switch (status.status) {
|
|
139
|
+
case health_1.State.STARTING:
|
|
140
|
+
statusCode = 503;
|
|
141
|
+
break;
|
|
142
|
+
case health_1.State.UP:
|
|
143
|
+
statusCode = 200;
|
|
144
|
+
break;
|
|
145
|
+
case health_1.State.DOWN:
|
|
146
|
+
statusCode = failingCode;
|
|
147
|
+
break;
|
|
148
|
+
case health_1.State.STOPPING:
|
|
149
|
+
statusCode = 503;
|
|
150
|
+
break;
|
|
151
|
+
case health_1.State.STOPPED:
|
|
152
|
+
statusCode = 503;
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
response.status(statusCode).send(status);
|
|
156
|
+
return response;
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=health.controller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health.controller.js","sourceRoot":"","sources":["../../src/controllers/health.controller.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './health.controller';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright IBM Corp. 2019. All Rights Reserved.
|
|
3
|
+
// Node module: @loopback/health
|
|
4
|
+
// This file is licensed under the MIT License.
|
|
5
|
+
// License text available at https://opensource.org/licenses/MIT
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
const tslib_1 = require("tslib");
|
|
8
|
+
tslib_1.__exportStar(require("./health.controller"), exports);
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/controllers/index.ts"],"names":[],"mappings":";AAAA,iDAAiD;AACjD,gCAAgC;AAChC,+CAA+C;AAC/C,gEAAgE;;;AAEhE,8DAAoC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Application, Component } from '@loopback/core';
|
|
2
|
+
import { HealthConfig } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* A component providing health status
|
|
5
|
+
*/
|
|
6
|
+
export declare class HealthComponent implements Component {
|
|
7
|
+
private application;
|
|
8
|
+
constructor(application: Application, healthConfig?: HealthConfig);
|
|
9
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright IBM Corp. 2019. All Rights Reserved.
|
|
3
|
+
// Node module: @loopback/health
|
|
4
|
+
// This file is licensed under the MIT License.
|
|
5
|
+
// License text available at https://opensource.org/licenses/MIT
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.HealthComponent = void 0;
|
|
8
|
+
const tslib_1 = require("tslib");
|
|
9
|
+
const health_1 = require("@cloudnative/health");
|
|
10
|
+
const core_1 = require("@loopback/core");
|
|
11
|
+
const controllers_1 = require("./controllers");
|
|
12
|
+
const keys_1 = require("./keys");
|
|
13
|
+
const observers_1 = require("./observers");
|
|
14
|
+
const types_1 = require("./types");
|
|
15
|
+
/**
|
|
16
|
+
* A component providing health status
|
|
17
|
+
*/
|
|
18
|
+
let HealthComponent = class HealthComponent {
|
|
19
|
+
constructor(application, healthConfig = {}) {
|
|
20
|
+
this.application = application;
|
|
21
|
+
// Bind the HealthCheck service
|
|
22
|
+
this.application
|
|
23
|
+
.bind(keys_1.HealthBindings.HEALTH_CHECKER)
|
|
24
|
+
.toClass(health_1.HealthChecker)
|
|
25
|
+
.inScope(core_1.BindingScope.SINGLETON);
|
|
26
|
+
// Bind the health observer
|
|
27
|
+
this.application.lifeCycleObserver(observers_1.HealthObserver);
|
|
28
|
+
const options = {
|
|
29
|
+
...types_1.DEFAULT_HEALTH_OPTIONS,
|
|
30
|
+
...healthConfig,
|
|
31
|
+
};
|
|
32
|
+
if (!options.disabled) {
|
|
33
|
+
this.application.controller(controllers_1.createHealthController(options));
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
HealthComponent = tslib_1.__decorate([
|
|
38
|
+
core_1.injectable({ tags: { [core_1.ContextTags.KEY]: keys_1.HealthBindings.COMPONENT } }),
|
|
39
|
+
tslib_1.__param(0, core_1.inject(core_1.CoreBindings.APPLICATION_INSTANCE)),
|
|
40
|
+
tslib_1.__param(1, core_1.config()),
|
|
41
|
+
tslib_1.__metadata("design:paramtypes", [core_1.Application, Object])
|
|
42
|
+
], HealthComponent);
|
|
43
|
+
exports.HealthComponent = HealthComponent;
|
|
44
|
+
//# sourceMappingURL=health.component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health.component.js","sourceRoot":"","sources":["../src/health.component.ts"],"names":[],"mappings":";AAAA,iDAAiD;AACjD,gCAAgC;AAChC,+CAA+C;AAC/C,gEAAgE;;;;AAEhE,gDAAkD;AAClD,yCASwB;AACxB,+CAAqD;AACrD,iCAAsC;AACtC,2CAA2C;AAC3C,mCAA4E;AAE5E;;GAEG;AAEH,IAAa,eAAe,GAA5B,MAAa,eAAe;IAC1B,YAEU,WAAwB,EAEhC,eAA6B,EAAE;QAFvB,gBAAW,GAAX,WAAW,CAAa;QAIhC,+BAA+B;QAC/B,IAAI,CAAC,WAAW;aACb,IAAI,CAAC,qBAAc,CAAC,cAAc,CAAC;aACnC,OAAO,CAAC,sBAAa,CAAC;aACtB,OAAO,CAAC,mBAAY,CAAC,SAAS,CAAC,CAAC;QAEnC,2BAA2B;QAC3B,IAAI,CAAC,WAAW,CAAC,iBAAiB,CAAC,0BAAc,CAAC,CAAC;QAEnD,MAAM,OAAO,GAAkB;YAC7B,GAAG,8BAAsB;YACzB,GAAG,YAAY;SAChB,CAAC;QACF,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE;YACrB,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,oCAAsB,CAAC,OAAO,CAAC,CAAC,CAAC;SAC9D;IACH,CAAC;CACF,CAAA;AAxBY,eAAe;IAD3B,iBAAU,CAAC,EAAC,IAAI,EAAE,EAAC,CAAC,kBAAW,CAAC,GAAG,CAAC,EAAE,qBAAc,CAAC,SAAS,EAAC,EAAC,CAAC;IAG7D,mBAAA,aAAM,CAAC,mBAAY,CAAC,oBAAoB,CAAC,CAAA;IAEzC,mBAAA,aAAM,EAAE,CAAA;6CADY,kBAAW;GAHvB,eAAe,CAwB3B;AAxBY,0CAAe"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright IBM Corp. 2019,2020. All Rights Reserved.
|
|
3
|
+
// Node module: @loopback/health
|
|
4
|
+
// This file is licensed under the MIT License.
|
|
5
|
+
// License text available at https://opensource.org/licenses/MIT
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
const tslib_1 = require("tslib");
|
|
8
|
+
/**
|
|
9
|
+
* A component to report health status using
|
|
10
|
+
* {@link https://github.com/CloudNativeJS/cloud-health | @cloudnative/health }.
|
|
11
|
+
*
|
|
12
|
+
* @packageDocumentation
|
|
13
|
+
*/
|
|
14
|
+
tslib_1.__exportStar(require("./health.component"), exports);
|
|
15
|
+
tslib_1.__exportStar(require("./keys"), exports);
|
|
16
|
+
tslib_1.__exportStar(require("./types"), exports);
|
|
17
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,sDAAsD;AACtD,gCAAgC;AAChC,+CAA+C;AAC/C,gEAAgE;;;AAEhE;;;;;GAKG;AAEH,6DAAmC;AACnC,iDAAuB;AACvB,kDAAwB"}
|
package/dist/keys.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { HealthChecker } from '@cloudnative/health';
|
|
2
|
+
import { BindingAddress, BindingKey } from '@loopback/core';
|
|
3
|
+
import { HealthComponent } from './health.component';
|
|
4
|
+
import { HealthConfig } from './types';
|
|
5
|
+
/**
|
|
6
|
+
* Binding keys used by this component.
|
|
7
|
+
*/
|
|
8
|
+
export declare namespace HealthBindings {
|
|
9
|
+
const COMPONENT: BindingKey<HealthComponent>;
|
|
10
|
+
const CONFIG: BindingAddress<HealthConfig>;
|
|
11
|
+
const HEALTH_CHECKER: BindingKey<HealthChecker>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Binding tags for health related services
|
|
15
|
+
*/
|
|
16
|
+
export declare namespace HealthTags {
|
|
17
|
+
/**
|
|
18
|
+
* Binding tag for liveness check functions
|
|
19
|
+
*/
|
|
20
|
+
const LIVE_CHECK = "health.liveCheck";
|
|
21
|
+
/**
|
|
22
|
+
* Binding tag for readiness check functions
|
|
23
|
+
*/
|
|
24
|
+
const READY_CHECK = "health.readyCheck";
|
|
25
|
+
}
|
package/dist/keys.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright IBM Corp. 2019,2020. All Rights Reserved.
|
|
3
|
+
// Node module: @loopback/health
|
|
4
|
+
// This file is licensed under the MIT License.
|
|
5
|
+
// License text available at https://opensource.org/licenses/MIT
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.HealthTags = exports.HealthBindings = void 0;
|
|
8
|
+
const core_1 = require("@loopback/core");
|
|
9
|
+
/**
|
|
10
|
+
* Binding keys used by this component.
|
|
11
|
+
*/
|
|
12
|
+
var HealthBindings;
|
|
13
|
+
(function (HealthBindings) {
|
|
14
|
+
HealthBindings.COMPONENT = core_1.BindingKey.create('components.HealthComponent');
|
|
15
|
+
HealthBindings.CONFIG = core_1.BindingKey.buildKeyForConfig(HealthBindings.COMPONENT.key);
|
|
16
|
+
HealthBindings.HEALTH_CHECKER = core_1.BindingKey.create('health.HeathChecker');
|
|
17
|
+
})(HealthBindings = exports.HealthBindings || (exports.HealthBindings = {}));
|
|
18
|
+
/**
|
|
19
|
+
* Binding tags for health related services
|
|
20
|
+
*/
|
|
21
|
+
var HealthTags;
|
|
22
|
+
(function (HealthTags) {
|
|
23
|
+
/**
|
|
24
|
+
* Binding tag for liveness check functions
|
|
25
|
+
*/
|
|
26
|
+
HealthTags.LIVE_CHECK = 'health.liveCheck';
|
|
27
|
+
/**
|
|
28
|
+
* Binding tag for readiness check functions
|
|
29
|
+
*/
|
|
30
|
+
HealthTags.READY_CHECK = 'health.readyCheck';
|
|
31
|
+
})(HealthTags = exports.HealthTags || (exports.HealthTags = {}));
|
|
32
|
+
//# sourceMappingURL=keys.js.map
|
package/dist/keys.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keys.js","sourceRoot":"","sources":["../src/keys.ts"],"names":[],"mappings":";AAAA,sDAAsD;AACtD,gCAAgC;AAChC,+CAA+C;AAC/C,gEAAgE;;;AAGhE,yCAA0D;AAI1D;;GAEG;AACH,IAAiB,cAAc,CAW9B;AAXD,WAAiB,cAAc;IAChB,wBAAS,GAAG,iBAAU,CAAC,MAAM,CACxC,4BAA4B,CAC7B,CAAC;IAEW,qBAAM,GACjB,iBAAU,CAAC,iBAAiB,CAAe,eAAA,SAAS,CAAC,GAAG,CAAC,CAAC;IAE/C,6BAAc,GAAG,iBAAU,CAAC,MAAM,CAC7C,qBAAqB,CACtB,CAAC;AACJ,CAAC,EAXgB,cAAc,GAAd,sBAAc,KAAd,sBAAc,QAW9B;AAED;;GAEG;AACH,IAAiB,UAAU,CAS1B;AATD,WAAiB,UAAU;IACzB;;OAEG;IACU,qBAAU,GAAG,kBAAkB,CAAC;IAC7C;;OAEG;IACU,sBAAW,GAAG,mBAAmB,CAAC;AACjD,CAAC,EATgB,UAAU,GAAV,kBAAU,KAAV,kBAAU,QAS1B"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { HealthChecker } from '@cloudnative/health';
|
|
2
|
+
import { ContextView, LifeCycleObserver } from '@loopback/core';
|
|
3
|
+
import { LiveCheck, ReadyCheck } from '../types';
|
|
4
|
+
export declare class HealthObserver implements LifeCycleObserver {
|
|
5
|
+
private healthChecker;
|
|
6
|
+
private liveChecks;
|
|
7
|
+
private readyChecks;
|
|
8
|
+
private eventEmitter;
|
|
9
|
+
private startupCheck;
|
|
10
|
+
private shutdownCheck;
|
|
11
|
+
constructor(healthChecker: HealthChecker, liveChecks: ContextView<LiveCheck>, readyChecks: ContextView<ReadyCheck>);
|
|
12
|
+
start(): Promise<void>;
|
|
13
|
+
stop(): void;
|
|
14
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright IBM Corp. 2019,2020. All Rights Reserved.
|
|
3
|
+
// Node module: @loopback/health
|
|
4
|
+
// This file is licensed under the MIT License.
|
|
5
|
+
// License text available at https://opensource.org/licenses/MIT
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.HealthObserver = void 0;
|
|
8
|
+
const tslib_1 = require("tslib");
|
|
9
|
+
const health_1 = require("@cloudnative/health");
|
|
10
|
+
const core_1 = require("@loopback/core");
|
|
11
|
+
const events_1 = require("events");
|
|
12
|
+
const keys_1 = require("../keys");
|
|
13
|
+
let HealthObserver = class HealthObserver {
|
|
14
|
+
constructor(healthChecker, liveChecks, readyChecks) {
|
|
15
|
+
this.healthChecker = healthChecker;
|
|
16
|
+
this.liveChecks = liveChecks;
|
|
17
|
+
this.readyChecks = readyChecks;
|
|
18
|
+
this.eventEmitter = new events_1.EventEmitter();
|
|
19
|
+
const startup = once(this.eventEmitter, 'startup');
|
|
20
|
+
const startupCheck = new health_1.StartupCheck('startup', () => startup);
|
|
21
|
+
this.startupCheck = this.healthChecker.registerStartupCheck(startupCheck);
|
|
22
|
+
const shutdown = once(this.eventEmitter, 'shutdown');
|
|
23
|
+
this.shutdownCheck = new health_1.ShutdownCheck('shutdown', () => shutdown);
|
|
24
|
+
}
|
|
25
|
+
async start() {
|
|
26
|
+
this.healthChecker.registerShutdownCheck(this.shutdownCheck);
|
|
27
|
+
const liveChecks = await this.liveChecks.values();
|
|
28
|
+
const liveCheckBindings = this.liveChecks.bindings;
|
|
29
|
+
let index = 0;
|
|
30
|
+
for (const lc of liveChecks) {
|
|
31
|
+
const name = liveCheckBindings[index].key;
|
|
32
|
+
const check = new health_1.LivenessCheck(name, lc);
|
|
33
|
+
this.healthChecker.registerLivenessCheck(check);
|
|
34
|
+
index++;
|
|
35
|
+
}
|
|
36
|
+
const readyChecks = await this.readyChecks.values();
|
|
37
|
+
const readyCheckBindings = this.readyChecks.bindings;
|
|
38
|
+
index = 0;
|
|
39
|
+
for (const rc of readyChecks) {
|
|
40
|
+
const name = readyCheckBindings[index].key;
|
|
41
|
+
const check = new health_1.ReadinessCheck(name, rc);
|
|
42
|
+
this.healthChecker.registerReadinessCheck(check);
|
|
43
|
+
index++;
|
|
44
|
+
}
|
|
45
|
+
this.eventEmitter.emit('startup');
|
|
46
|
+
await this.startupCheck;
|
|
47
|
+
}
|
|
48
|
+
stop() {
|
|
49
|
+
this.eventEmitter.emit('shutdown');
|
|
50
|
+
// Fix a potential memory leak caused by
|
|
51
|
+
// https://github.com/CloudNativeJS/cloud-health/blob/2.1.2/src/healthcheck/HealthChecker.ts#L118
|
|
52
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
53
|
+
const onShutdownRequest = this.healthChecker.onShutdownRequest;
|
|
54
|
+
if (onShutdownRequest != null) {
|
|
55
|
+
// Remove the listener from the current process
|
|
56
|
+
process.removeListener('SIGTERM', onShutdownRequest);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
HealthObserver = tslib_1.__decorate([
|
|
61
|
+
tslib_1.__param(0, core_1.inject(keys_1.HealthBindings.HEALTH_CHECKER)),
|
|
62
|
+
tslib_1.__param(1, core_1.inject.view(core_1.filterByTag(keys_1.HealthTags.LIVE_CHECK))),
|
|
63
|
+
tslib_1.__param(2, core_1.inject.view(core_1.filterByTag(keys_1.HealthTags.READY_CHECK))),
|
|
64
|
+
tslib_1.__metadata("design:paramtypes", [health_1.HealthChecker,
|
|
65
|
+
core_1.ContextView,
|
|
66
|
+
core_1.ContextView])
|
|
67
|
+
], HealthObserver);
|
|
68
|
+
exports.HealthObserver = HealthObserver;
|
|
69
|
+
function once(emitter, event) {
|
|
70
|
+
return events_1.once(emitter, event);
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=health.observer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health.observer.js","sourceRoot":"","sources":["../../src/observers/health.observer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './health.observer';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright IBM Corp. 2019. All Rights Reserved.
|
|
3
|
+
// Node module: @loopback/health
|
|
4
|
+
// This file is licensed under the MIT License.
|
|
5
|
+
// License text available at https://opensource.org/licenses/MIT
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
const tslib_1 = require("tslib");
|
|
8
|
+
tslib_1.__exportStar(require("./health.observer"), exports);
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/observers/index.ts"],"names":[],"mappings":";AAAA,iDAAiD;AACjD,gCAAgC;AAChC,+CAA+C;AAC/C,gEAAgE;;;AAEhE,4DAAkC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Options for health component
|
|
3
|
+
*/
|
|
4
|
+
export declare type HealthOptions = {
|
|
5
|
+
disabled?: boolean;
|
|
6
|
+
healthPath: string;
|
|
7
|
+
readyPath: string;
|
|
8
|
+
livePath: string;
|
|
9
|
+
openApiSpec?: boolean;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Configuration for health component with optional properties
|
|
13
|
+
*/
|
|
14
|
+
export declare type HealthConfig = Partial<HealthOptions>;
|
|
15
|
+
export declare const DEFAULT_HEALTH_OPTIONS: HealthOptions;
|
|
16
|
+
/**
|
|
17
|
+
* Functions for liveness check
|
|
18
|
+
*/
|
|
19
|
+
export declare type LiveCheck = () => Promise<void>;
|
|
20
|
+
/**
|
|
21
|
+
* Functions for readiness check
|
|
22
|
+
*/
|
|
23
|
+
export declare type ReadyCheck = () => Promise<void>;
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright IBM Corp. 2019. All Rights Reserved.
|
|
3
|
+
// Node module: @loopback/health
|
|
4
|
+
// This file is licensed under the MIT License.
|
|
5
|
+
// License text available at https://opensource.org/licenses/MIT
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.DEFAULT_HEALTH_OPTIONS = void 0;
|
|
8
|
+
exports.DEFAULT_HEALTH_OPTIONS = {
|
|
9
|
+
healthPath: '/health',
|
|
10
|
+
readyPath: '/ready',
|
|
11
|
+
livePath: '/live',
|
|
12
|
+
openApiSpec: false,
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";AAAA,iDAAiD;AACjD,gCAAgC;AAChC,+CAA+C;AAC/C,gEAAgE;;;AAkBnD,QAAA,sBAAsB,GAAkB;IACnD,UAAU,EAAE,SAAS;IACrB,SAAS,EAAE,QAAQ;IACnB,QAAQ,EAAE,OAAO;IACjB,WAAW,EAAE,KAAK;CACnB,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@loopback/health",
|
|
3
|
+
"description": "An extension exposes health check related endpoints with LoopBack 4",
|
|
4
|
+
"version": "0.8.3",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"LoopBack",
|
|
7
|
+
"Cloud Native",
|
|
8
|
+
"Health"
|
|
9
|
+
],
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"main": "dist/index.js",
|
|
12
|
+
"types": "dist/index.d.ts",
|
|
13
|
+
"author": "IBM Corp.",
|
|
14
|
+
"copyright.owner": "IBM Corp.",
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "https://github.com/loopbackio/loopback-next.git",
|
|
18
|
+
"directory": "extensions/health"
|
|
19
|
+
},
|
|
20
|
+
"engines": {
|
|
21
|
+
"node": "^10.16 || 12 || 14 || 16"
|
|
22
|
+
},
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "lb-tsc",
|
|
25
|
+
"clean": "lb-clean loopback-extension-health*.tgz dist *.tsbuildinfo package",
|
|
26
|
+
"pretest": "npm run build",
|
|
27
|
+
"test": "lb-mocha \"dist/__tests__/**/*.js\"",
|
|
28
|
+
"verify": "npm pack && tar xf loopback-extension-health*.tgz && tree package && npm run clean",
|
|
29
|
+
"demo": "./src/__examples__/demo.sh"
|
|
30
|
+
},
|
|
31
|
+
"publishConfig": {
|
|
32
|
+
"access": "public"
|
|
33
|
+
},
|
|
34
|
+
"files": [
|
|
35
|
+
"README.md",
|
|
36
|
+
"dist",
|
|
37
|
+
"src",
|
|
38
|
+
"!*/__tests__"
|
|
39
|
+
],
|
|
40
|
+
"peerDependencies": {
|
|
41
|
+
"@loopback/core": "^2.17.0",
|
|
42
|
+
"@loopback/rest": "^10.0.1"
|
|
43
|
+
},
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"@cloudnative/health": "^2.1.2",
|
|
46
|
+
"tslib": "^2.3.1"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@loopback/build": "^7.0.1",
|
|
50
|
+
"@loopback/core": "^2.17.0",
|
|
51
|
+
"@loopback/eslint-config": "^11.0.1",
|
|
52
|
+
"@loopback/rest": "^10.0.1",
|
|
53
|
+
"@loopback/testlab": "^3.4.3",
|
|
54
|
+
"@types/node": "^10.17.60"
|
|
55
|
+
},
|
|
56
|
+
"gitHead": "1df36bb1ee2e513d9e197bd6010c4cfb296d50b8"
|
|
57
|
+
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
// Copyright IBM Corp. 2019. All Rights Reserved.
|
|
2
|
+
// Node module: @loopback/health
|
|
3
|
+
// This file is licensed under the MIT License.
|
|
4
|
+
// License text available at https://opensource.org/licenses/MIT
|
|
5
|
+
|
|
6
|
+
import {HealthChecker, HealthStatus, State} from '@cloudnative/health';
|
|
7
|
+
import {BindingScope, Constructor, inject, injectable} from '@loopback/core';
|
|
8
|
+
import {
|
|
9
|
+
get,
|
|
10
|
+
OperationObject,
|
|
11
|
+
Response,
|
|
12
|
+
ResponseObject,
|
|
13
|
+
RestBindings,
|
|
14
|
+
SchemaObject,
|
|
15
|
+
} from '@loopback/rest';
|
|
16
|
+
import {HealthBindings} from '../keys';
|
|
17
|
+
import {DEFAULT_HEALTH_OPTIONS, HealthOptions} from '../types';
|
|
18
|
+
|
|
19
|
+
function getHealthResponseObject() {
|
|
20
|
+
/**
|
|
21
|
+
* OpenAPI definition of health response schema
|
|
22
|
+
*/
|
|
23
|
+
const HEALTH_RESPONSE_SCHEMA: SchemaObject = {
|
|
24
|
+
type: 'object',
|
|
25
|
+
properties: {
|
|
26
|
+
status: {type: 'string'},
|
|
27
|
+
checks: {
|
|
28
|
+
type: 'array',
|
|
29
|
+
items: {
|
|
30
|
+
type: 'object',
|
|
31
|
+
properties: {
|
|
32
|
+
name: {type: 'string'},
|
|
33
|
+
state: {type: 'string'},
|
|
34
|
+
data: {
|
|
35
|
+
type: 'object',
|
|
36
|
+
properties: {
|
|
37
|
+
reason: {type: 'string'},
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* OpenAPI definition of health response
|
|
48
|
+
*/
|
|
49
|
+
const HEALTH_RESPONSE: ResponseObject = {
|
|
50
|
+
description: 'Health Response',
|
|
51
|
+
content: {
|
|
52
|
+
'application/json': {
|
|
53
|
+
schema: HEALTH_RESPONSE_SCHEMA,
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
return HEALTH_RESPONSE;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* OpenAPI spec for health endpoints
|
|
63
|
+
*/
|
|
64
|
+
const HEALTH_SPEC: OperationObject = {
|
|
65
|
+
// response object needs to be cloned because the oas-validator throws an
|
|
66
|
+
// error if the same object is referenced twice
|
|
67
|
+
responses: {
|
|
68
|
+
'200': getHealthResponseObject(),
|
|
69
|
+
'500': getHealthResponseObject(),
|
|
70
|
+
'503': getHealthResponseObject(),
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* OpenAPI spec to hide endpoints
|
|
76
|
+
*/
|
|
77
|
+
const HIDDEN_SPEC: OperationObject = {
|
|
78
|
+
responses: {},
|
|
79
|
+
'x-visibility': 'undocumented',
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* A factory function to create a controller class for health endpoints. This
|
|
84
|
+
* makes it possible to customize decorations such as `@get` with a dynamic
|
|
85
|
+
* path value not known at compile time.
|
|
86
|
+
*
|
|
87
|
+
* @param options - Options for health endpoints
|
|
88
|
+
*/
|
|
89
|
+
export function createHealthController(
|
|
90
|
+
options: HealthOptions = DEFAULT_HEALTH_OPTIONS,
|
|
91
|
+
): Constructor<unknown> {
|
|
92
|
+
const spec = options.openApiSpec ? HEALTH_SPEC : HIDDEN_SPEC;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Controller for health endpoints
|
|
96
|
+
*/
|
|
97
|
+
@injectable({scope: BindingScope.SINGLETON})
|
|
98
|
+
class HealthController {
|
|
99
|
+
constructor(
|
|
100
|
+
@inject(HealthBindings.HEALTH_CHECKER)
|
|
101
|
+
private healthChecker: HealthChecker,
|
|
102
|
+
) {}
|
|
103
|
+
|
|
104
|
+
@get(options.healthPath, spec)
|
|
105
|
+
async health(@inject(RestBindings.Http.RESPONSE) response: Response) {
|
|
106
|
+
const status = await this.healthChecker.getStatus();
|
|
107
|
+
return handleStatus(response, status);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
@get(options.readyPath, spec)
|
|
111
|
+
async ready(@inject(RestBindings.Http.RESPONSE) response: Response) {
|
|
112
|
+
const status = await this.healthChecker.getReadinessStatus();
|
|
113
|
+
return handleStatus(response, status, 503);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
@get(options.livePath, spec)
|
|
117
|
+
async live(@inject(RestBindings.Http.RESPONSE) response: Response) {
|
|
118
|
+
const status = await this.healthChecker.getLivenessStatus();
|
|
119
|
+
return handleStatus(response, status, 500);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return HealthController;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Create response for the given status
|
|
128
|
+
* @param response - Http response
|
|
129
|
+
* @param status - Health status
|
|
130
|
+
* @param failingCode - Status code for `DOWN`
|
|
131
|
+
*/
|
|
132
|
+
function handleStatus(
|
|
133
|
+
response: Response,
|
|
134
|
+
status: HealthStatus,
|
|
135
|
+
failingCode: 500 | 503 = 503,
|
|
136
|
+
) {
|
|
137
|
+
let statusCode = 200;
|
|
138
|
+
switch (status.status) {
|
|
139
|
+
case State.STARTING:
|
|
140
|
+
statusCode = 503;
|
|
141
|
+
break;
|
|
142
|
+
case State.UP:
|
|
143
|
+
statusCode = 200;
|
|
144
|
+
break;
|
|
145
|
+
case State.DOWN:
|
|
146
|
+
statusCode = failingCode;
|
|
147
|
+
break;
|
|
148
|
+
case State.STOPPING:
|
|
149
|
+
statusCode = 503;
|
|
150
|
+
break;
|
|
151
|
+
case State.STOPPED:
|
|
152
|
+
statusCode = 503;
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
response.status(statusCode).send(status);
|
|
156
|
+
return response;
|
|
157
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// Copyright IBM Corp. 2019. All Rights Reserved.
|
|
2
|
+
// Node module: @loopback/health
|
|
3
|
+
// This file is licensed under the MIT License.
|
|
4
|
+
// License text available at https://opensource.org/licenses/MIT
|
|
5
|
+
|
|
6
|
+
import {HealthChecker} from '@cloudnative/health';
|
|
7
|
+
import {
|
|
8
|
+
Application,
|
|
9
|
+
BindingScope,
|
|
10
|
+
Component,
|
|
11
|
+
config,
|
|
12
|
+
ContextTags,
|
|
13
|
+
CoreBindings,
|
|
14
|
+
inject,
|
|
15
|
+
injectable,
|
|
16
|
+
} from '@loopback/core';
|
|
17
|
+
import {createHealthController} from './controllers';
|
|
18
|
+
import {HealthBindings} from './keys';
|
|
19
|
+
import {HealthObserver} from './observers';
|
|
20
|
+
import {DEFAULT_HEALTH_OPTIONS, HealthConfig, HealthOptions} from './types';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* A component providing health status
|
|
24
|
+
*/
|
|
25
|
+
@injectable({tags: {[ContextTags.KEY]: HealthBindings.COMPONENT}})
|
|
26
|
+
export class HealthComponent implements Component {
|
|
27
|
+
constructor(
|
|
28
|
+
@inject(CoreBindings.APPLICATION_INSTANCE)
|
|
29
|
+
private application: Application,
|
|
30
|
+
@config()
|
|
31
|
+
healthConfig: HealthConfig = {},
|
|
32
|
+
) {
|
|
33
|
+
// Bind the HealthCheck service
|
|
34
|
+
this.application
|
|
35
|
+
.bind(HealthBindings.HEALTH_CHECKER)
|
|
36
|
+
.toClass(HealthChecker)
|
|
37
|
+
.inScope(BindingScope.SINGLETON);
|
|
38
|
+
|
|
39
|
+
// Bind the health observer
|
|
40
|
+
this.application.lifeCycleObserver(HealthObserver);
|
|
41
|
+
|
|
42
|
+
const options: HealthOptions = {
|
|
43
|
+
...DEFAULT_HEALTH_OPTIONS,
|
|
44
|
+
...healthConfig,
|
|
45
|
+
};
|
|
46
|
+
if (!options.disabled) {
|
|
47
|
+
this.application.controller(createHealthController(options));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// Copyright IBM Corp. 2019,2020. All Rights Reserved.
|
|
2
|
+
// Node module: @loopback/health
|
|
3
|
+
// This file is licensed under the MIT License.
|
|
4
|
+
// License text available at https://opensource.org/licenses/MIT
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* A component to report health status using
|
|
8
|
+
* {@link https://github.com/CloudNativeJS/cloud-health | @cloudnative/health }.
|
|
9
|
+
*
|
|
10
|
+
* @packageDocumentation
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
export * from './health.component';
|
|
14
|
+
export * from './keys';
|
|
15
|
+
export * from './types';
|
package/src/keys.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// Copyright IBM Corp. 2019,2020. All Rights Reserved.
|
|
2
|
+
// Node module: @loopback/health
|
|
3
|
+
// This file is licensed under the MIT License.
|
|
4
|
+
// License text available at https://opensource.org/licenses/MIT
|
|
5
|
+
|
|
6
|
+
import {HealthChecker} from '@cloudnative/health';
|
|
7
|
+
import {BindingAddress, BindingKey} from '@loopback/core';
|
|
8
|
+
import {HealthComponent} from './health.component';
|
|
9
|
+
import {HealthConfig} from './types';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Binding keys used by this component.
|
|
13
|
+
*/
|
|
14
|
+
export namespace HealthBindings {
|
|
15
|
+
export const COMPONENT = BindingKey.create<HealthComponent>(
|
|
16
|
+
'components.HealthComponent',
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
export const CONFIG: BindingAddress<HealthConfig> =
|
|
20
|
+
BindingKey.buildKeyForConfig<HealthConfig>(COMPONENT.key);
|
|
21
|
+
|
|
22
|
+
export const HEALTH_CHECKER = BindingKey.create<HealthChecker>(
|
|
23
|
+
'health.HeathChecker',
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Binding tags for health related services
|
|
29
|
+
*/
|
|
30
|
+
export namespace HealthTags {
|
|
31
|
+
/**
|
|
32
|
+
* Binding tag for liveness check functions
|
|
33
|
+
*/
|
|
34
|
+
export const LIVE_CHECK = 'health.liveCheck';
|
|
35
|
+
/**
|
|
36
|
+
* Binding tag for readiness check functions
|
|
37
|
+
*/
|
|
38
|
+
export const READY_CHECK = 'health.readyCheck';
|
|
39
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// Copyright IBM Corp. 2019,2020. All Rights Reserved.
|
|
2
|
+
// Node module: @loopback/health
|
|
3
|
+
// This file is licensed under the MIT License.
|
|
4
|
+
// License text available at https://opensource.org/licenses/MIT
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
HealthChecker,
|
|
8
|
+
LivenessCheck,
|
|
9
|
+
ReadinessCheck,
|
|
10
|
+
ShutdownCheck,
|
|
11
|
+
StartupCheck,
|
|
12
|
+
} from '@cloudnative/health';
|
|
13
|
+
import {
|
|
14
|
+
ContextView,
|
|
15
|
+
filterByTag,
|
|
16
|
+
inject,
|
|
17
|
+
LifeCycleObserver,
|
|
18
|
+
} from '@loopback/core';
|
|
19
|
+
import {EventEmitter, once as onceGeneric} from 'events';
|
|
20
|
+
import {HealthBindings, HealthTags} from '../keys';
|
|
21
|
+
import {LiveCheck, ReadyCheck} from '../types';
|
|
22
|
+
|
|
23
|
+
export class HealthObserver implements LifeCycleObserver {
|
|
24
|
+
private eventEmitter = new EventEmitter();
|
|
25
|
+
private startupCheck: Promise<void>;
|
|
26
|
+
private shutdownCheck: ShutdownCheck;
|
|
27
|
+
|
|
28
|
+
constructor(
|
|
29
|
+
@inject(HealthBindings.HEALTH_CHECKER) private healthChecker: HealthChecker,
|
|
30
|
+
|
|
31
|
+
@inject.view(filterByTag(HealthTags.LIVE_CHECK))
|
|
32
|
+
private liveChecks: ContextView<LiveCheck>,
|
|
33
|
+
|
|
34
|
+
@inject.view(filterByTag(HealthTags.READY_CHECK))
|
|
35
|
+
private readyChecks: ContextView<ReadyCheck>,
|
|
36
|
+
) {
|
|
37
|
+
const startup = once(
|
|
38
|
+
this.eventEmitter,
|
|
39
|
+
'startup',
|
|
40
|
+
) as unknown as Promise<void>;
|
|
41
|
+
const startupCheck = new StartupCheck('startup', () => startup);
|
|
42
|
+
this.startupCheck = this.healthChecker.registerStartupCheck(startupCheck);
|
|
43
|
+
const shutdown = once(this.eventEmitter, 'shutdown');
|
|
44
|
+
this.shutdownCheck = new ShutdownCheck('shutdown', () => shutdown);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async start() {
|
|
48
|
+
this.healthChecker.registerShutdownCheck(this.shutdownCheck);
|
|
49
|
+
const liveChecks = await this.liveChecks.values();
|
|
50
|
+
const liveCheckBindings = this.liveChecks.bindings;
|
|
51
|
+
let index = 0;
|
|
52
|
+
for (const lc of liveChecks) {
|
|
53
|
+
const name = liveCheckBindings[index].key;
|
|
54
|
+
const check = new LivenessCheck(name, lc);
|
|
55
|
+
this.healthChecker.registerLivenessCheck(check);
|
|
56
|
+
index++;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const readyChecks = await this.readyChecks.values();
|
|
60
|
+
const readyCheckBindings = this.readyChecks.bindings;
|
|
61
|
+
index = 0;
|
|
62
|
+
for (const rc of readyChecks) {
|
|
63
|
+
const name = readyCheckBindings[index].key;
|
|
64
|
+
const check = new ReadinessCheck(name, rc);
|
|
65
|
+
this.healthChecker.registerReadinessCheck(check);
|
|
66
|
+
index++;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
this.eventEmitter.emit('startup');
|
|
70
|
+
await this.startupCheck;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
stop() {
|
|
74
|
+
this.eventEmitter.emit('shutdown');
|
|
75
|
+
// Fix a potential memory leak caused by
|
|
76
|
+
// https://github.com/CloudNativeJS/cloud-health/blob/2.1.2/src/healthcheck/HealthChecker.ts#L118
|
|
77
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
78
|
+
const onShutdownRequest = (this.healthChecker as any).onShutdownRequest;
|
|
79
|
+
if (onShutdownRequest != null) {
|
|
80
|
+
// Remove the listener from the current process
|
|
81
|
+
process.removeListener('SIGTERM', onShutdownRequest);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function once(emitter: EventEmitter, event: string | symbol): Promise<void> {
|
|
87
|
+
return onceGeneric(emitter, event) as unknown as Promise<void>;
|
|
88
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// Copyright IBM Corp. 2019. All Rights Reserved.
|
|
2
|
+
// Node module: @loopback/health
|
|
3
|
+
// This file is licensed under the MIT License.
|
|
4
|
+
// License text available at https://opensource.org/licenses/MIT
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Options for health component
|
|
8
|
+
*/
|
|
9
|
+
export type HealthOptions = {
|
|
10
|
+
disabled?: boolean;
|
|
11
|
+
healthPath: string;
|
|
12
|
+
readyPath: string;
|
|
13
|
+
livePath: string;
|
|
14
|
+
openApiSpec?: boolean;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Configuration for health component with optional properties
|
|
19
|
+
*/
|
|
20
|
+
export type HealthConfig = Partial<HealthOptions>;
|
|
21
|
+
|
|
22
|
+
export const DEFAULT_HEALTH_OPTIONS: HealthOptions = {
|
|
23
|
+
healthPath: '/health',
|
|
24
|
+
readyPath: '/ready',
|
|
25
|
+
livePath: '/live',
|
|
26
|
+
openApiSpec: false,
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Functions for liveness check
|
|
31
|
+
*/
|
|
32
|
+
export type LiveCheck = () => Promise<void>;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Functions for readiness check
|
|
36
|
+
*/
|
|
37
|
+
export type ReadyCheck = () => Promise<void>;
|