Skip to content

Commit

Permalink
feat(terminus): Add terminus package
Browse files Browse the repository at this point in the history
  • Loading branch information
EmilienLeroy authored and Romakita committed Aug 22, 2021
1 parent 0a71004 commit 25eb3c1
Show file tree
Hide file tree
Showing 12 changed files with 316 additions and 0 deletions.
4 changes: 4 additions & 0 deletions packages/terminus/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
src
test
tsconfig.compile.json
tsconfig.json
11 changes: 11 additions & 0 deletions packages/terminus/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# `terminus`

> TODO: description
## Usage

```
const terminus = require('terminus');
// TODO: DEMONSTRATE API
```
22 changes: 22 additions & 0 deletions packages/terminus/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"name": "@tsed/terminus",
"version": "6.38.5",
"description": "Adds graceful shutdown and Kubernetes readiness / liveness checks for any HTTP applications.",
"author": "Emilien Leroy <emilien1005@hotmail.fr>",
"main": "./lib/index.js",
"typings": "./lib/index.d.ts",
"scripts": {
"build": "tsc --build tsconfig.compile.json",
"start": "ts-node -r tsconfig-paths/register test/app/index.ts"
},
"private": false,
"devDependencies": {
"@tsed/common": "6.45.1",
"@tsed/openspec": "6.45.1",
"@tsed/schema": "6.45.1"
},
"dependencies": {
"@godaddy/terminus": "^4.7.1",
"tslib": "2.1.0"
}
}
74 changes: 74 additions & 0 deletions packages/terminus/src/TerminusModule.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import {createTerminus} from "@godaddy/terminus";
import {Configuration, HttpServer, HttpsServer, Inject, InjectorService, Module, OnInit} from "@tsed/common";

@Module()
export class TerminusModule implements OnInit {
@Configuration()
private configuration: Configuration;

@Inject()
private injector: InjectorService;

@Inject(HttpServer)
private httpServer: HttpServer;

@Inject(HttpsServer)
private httpsServer: HttpsServer;

public $onInit() {
this.mount(this.httpServer, this.httpsServer);
}

private mount(httpServer?: HttpServer, httpsServer?: HttpsServer) {
const {terminus} = this.configuration;
const terminusConfig = {
logger: this.injector.logger as any,
healthChecks: this.getHealths(),
onSignal: this.execShutdown("onSignal"),
onShutdown: this.execShutdown("onShutdown"),
beforeShutdown: this.execShutdown("beforeShutdown"),
onSendFailureDuringShutdown: this.execShutdown("onSendFailureDuringShutdown"),
...terminus
};

if (httpServer) {
createTerminus(httpServer, terminusConfig);
}

if (httpsServer) {
createTerminus(httpsServer, terminusConfig);
}
}

private getProviders(name: string) {
return this.injector.getProviders().filter((provider) => {
return provider.store.get(name);
});
}

private getStore(name: string) {
return this.injector
.getProviders()
.map((provider) => provider.store.get(name))
.filter((x) => !!x)
.flat();
}

private getHealths() {
const healths: {[k: string]: () => Promise<any>} = {};

this.getProviders("terminus").forEach((provider) => {
Object.keys(provider.store.get("terminus")).forEach((name) => {
healths[`${provider.path}${name}`] = provider.store.get("terminus")[name];
});
});

return healths;
}

private execShutdown(name: string) {
return async () => {
this.getStore(name).forEach((func) => func());
};
}
}
30 changes: 30 additions & 0 deletions packages/terminus/src/decorators/health.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import {Store} from "@tsed/core";

/**
* Create a readiness / liveness checks.
*
* ```ts
* import { Health } from "@tsed/terminus";
*
* @Controller("/mongo")
* class MongoCtrl {
* @Health("/health")
* health() {
* // Here check the mongo health
* return Promise.resolve();
* }
* }
*
* @param name
* @decorator
* @terminus
*/
export function Health(name: string): MethodDecorator {
return <Function>(target: Object, propertyKey: string, descriptor: TypedPropertyDescriptor<Function>) => {
if (descriptor.value) {
Store.from(target).merge("terminus", {
[name]: descriptor.value
});
}
};
}
52 changes: 52 additions & 0 deletions packages/terminus/src/decorators/shutdown.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import {Store} from "@tsed/core";

function register(name: string) {
return <Function>(target: Object, propertyKey: string, descriptor: TypedPropertyDescriptor<Function>) => {
if (descriptor.value) {
const store = Store.from(target);
const values = store.get(name, []);

store.merge(name, [...values, descriptor.value]);
}
};
}

/**
* Listen the `beforeShutdown` terminus event.
*
* @decorator
* @terminus
*/
export function BeforeShutdown(): MethodDecorator {
return register("beforeShutdown");
}

/**
* Listen the `onSignal` terminus event.
*
* @decorator
* @terminus
*/
export function OnSignal(): MethodDecorator {
return register("onSignal");
}

/**
* Listen the `onShutdown` terminus event.
*
* @decorator
* @terminus
*/
export function OnShutdown(): MethodDecorator {
return register("onShutdown");
}

/**
* Listen the `onSendFailureDuringShutdown` terminus event.
*
* @decorator
* @terminus
*/
export function OnSendFailureDuringShutdown(): MethodDecorator {
return register("onSendFailureDuringShutdown");
}
4 changes: 4 additions & 0 deletions packages/terminus/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export * from "./decorators/health";
export * from "./decorators/shutdown";
export * from "./interfaces";
export * from "./TerminusModule";
6 changes: 6 additions & 0 deletions packages/terminus/src/interfaces/TerminusSettings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import {TerminusOptions} from "@godaddy/terminus";

export type TerminusSettings = Omit<
TerminusOptions,
"healthChecks" | "onSignal" | "onSendFailureDuringShutdown" | "onShutdown" | "beforeShutdown" | "onSigterm"
>;
11 changes: 11 additions & 0 deletions packages/terminus/src/interfaces/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import {TerminusSettings} from "./TerminusSettings";

declare global {
namespace TsED {
interface Configuration {
terminus: TerminusSettings;
}
}
}

export * from "./TerminusSettings";
72 changes: 72 additions & 0 deletions packages/terminus/test/app/Server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import {HealthCheckError} from "@godaddy/terminus";
import "@tsed/ajv";
import {Controller, PlatformApplication} from "@tsed/common";
import {Configuration, Inject} from "@tsed/di";
import bodyParser from "body-parser";
import cookieParser from "cookie-parser";
import {Application} from "express";
import {BeforeShutdown, Health, OnSendFailureDuringShutdown, OnShutdown, OnSignal} from "../../src";

export const rootDir = __dirname;

@Controller("/mongo")
class MongoCtrl {
@Health("/health")
health() {
return Promise.resolve();
}
}

@Controller("/redis")
class RedisCtrl {
@Health("/health")
health() {
return Promise.reject(new HealthCheckError("failed", {
redis: "down"
}));
}

@BeforeShutdown()
beforeShutdow() {
console.log("called before shutdown");
}

@OnSignal()
onSignal() {
console.log("called on signal");
}

@OnShutdown()
onShutdown() {
console.log("called on shutdown");
}

@OnSendFailureDuringShutdown()
onSendFailureDuringShutdown() {
console.log("on send failure during shutdown");
}
}


@Configuration({
port: 8081,
mount: {
"/": [RedisCtrl, MongoCtrl]
},
terminus: {
signal: "SIGTERM",
statusError: 500,
sendFailuresDuringShutdown: false
},
middlewares: [
cookieParser(),
bodyParser.json(),
bodyParser.urlencoded({
extended: true
})
]
})
export class Server {
@Inject()
app: PlatformApplication<Application>;
}
17 changes: 17 additions & 0 deletions packages/terminus/test/app/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import {$log} from "@tsed/common";
import {PlatformExpress} from "@tsed/platform-express";
import {Server} from "./Server";

if (process.env.NODE_ENV !== "test") {
async function bootstrap() {
try {
const platform = await PlatformExpress.bootstrap(Server);
await platform.listen();
$log.debug("Server initialized");
} catch (er) {
$log.error(er);
}
}

bootstrap();
}
13 changes: 13 additions & 0 deletions packages/terminus/tsconfig.compile.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"extends": "../../tsconfig.compile.json",
"compilerOptions": {
"rootDir": "src",
"outDir": "lib"
},
"exclude": [
"node_modules",
"test",
"lib",
"**/*.spec.ts"
]
}

0 comments on commit 25eb3c1

Please sign in to comment.