Skip to content

Commit 42485fb

Browse files
committed
Added /healthz JSON response for heartbeat data. #1940
1 parent c6f054a commit 42485fb

File tree

3 files changed

+50
-4
lines changed

3 files changed

+50
-4
lines changed

src/node/app/health.ts

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import * as http from "http"
2+
import { HttpCode, HttpError } from "../../common/http"
3+
import { HttpProvider, HttpResponse, Route, Heart, HttpProviderOptions } from "../http"
4+
5+
/**
6+
* Check the heartbeat.
7+
*/
8+
export class HealthHttpProvider extends HttpProvider {
9+
10+
public constructor(
11+
options: HttpProviderOptions,
12+
private readonly heart: Heart
13+
) {
14+
super(options)
15+
}
16+
17+
private alive(): Boolean {
18+
const now = Date.now()
19+
return (now - this.heart.lastHeartbeat < this.heart.heartbeatInterval)
20+
}
21+
22+
public async handleRequest(route: Route, request: http.IncomingMessage): Promise<HttpResponse> {
23+
if (!this.authenticated(request)) {
24+
if (this.isRoot(route)) {
25+
return { redirect: "/login", query: { to: route.fullPath } }
26+
}
27+
throw new HttpError("Unauthorized", HttpCode.Unauthorized)
28+
}
29+
30+
const result = {
31+
cache: false,
32+
mime: 'application/json',
33+
content: {
34+
status: (this.alive()) ? 'alive' : 'expired',
35+
lastHeartbeat: this.heart.lastHeartbeat
36+
37+
}
38+
}
39+
40+
return result
41+
42+
}
43+
}

src/node/entry.ts

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { ProxyHttpProvider } from "./app/proxy"
77
import { StaticHttpProvider } from "./app/static"
88
import { UpdateHttpProvider } from "./app/update"
99
import { VscodeHttpProvider } from "./app/vscode"
10+
import { HealthHttpProvider } from "./app/health"
1011
import { Args, bindAddrFromAllSources, optionDescriptions, parse, readConfigFile, setDefaults } from "./cli"
1112
import { AuthType, HttpServer, HttpServerOptions } from "./http"
1213
import { loadPlugins } from "./plugin"
@@ -78,6 +79,7 @@ const main = async (args: Args, cliArgs: Args, configArgs: Args): Promise<void>
7879
httpServer.registerHttpProvider("/proxy", ProxyHttpProvider)
7980
httpServer.registerHttpProvider("/login", LoginHttpProvider, args.config!, envPassword)
8081
httpServer.registerHttpProvider("/static", StaticHttpProvider)
82+
httpServer.registerHttpProvider("/healthz", HealthHttpProvider, httpServer.heart)
8183

8284
await loadPlugins(httpServer, args)
8385

src/node/http.ts

+5-4
Original file line numberDiff line numberDiff line change
@@ -395,8 +395,8 @@ export abstract class HttpProvider {
395395
*/
396396
export class Heart {
397397
private heartbeatTimer?: NodeJS.Timeout
398-
private heartbeatInterval = 60000
399-
private lastHeartbeat = 0
398+
public heartbeatInterval = 60000
399+
public lastHeartbeat = 0
400400

401401
public constructor(private readonly heartbeatPath: string, private readonly isActive: () => Promise<boolean>) {}
402402

@@ -457,7 +457,7 @@ export class HttpServer {
457457
private listenPromise: Promise<string | null> | undefined
458458
public readonly protocol: "http" | "https"
459459
private readonly providers = new Map<string, HttpProvider>()
460-
private readonly heart: Heart
460+
public readonly heart: Heart
461461
private readonly socketProvider = new SocketProxyProvider()
462462

463463
/**
@@ -602,8 +602,9 @@ export class HttpServer {
602602
}
603603

604604
private onRequest = async (request: http.IncomingMessage, response: http.ServerResponse): Promise<void> => {
605-
this.heart.beat()
606605
const route = this.parseUrl(request)
606+
if (route.providerBase !== '/healthz')
607+
this.heart.beat()
607608
const write = (payload: HttpResponse): void => {
608609
response.writeHead(payload.redirect ? HttpCode.Redirect : payload.code || HttpCode.Ok, {
609610
"Content-Type": payload.mime || getMediaMime(payload.filePath),

0 commit comments

Comments
 (0)