From 8dc15aae58a74fcca6a978b41b13b1bace21b8e8 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Fri, 17 May 2024 11:19:40 +0200 Subject: [PATCH 01/26] backend-app-api: httpRouter add healthCheckConfig Signed-off-by: Vincenzo Scamporlino --- .../httpRouter/httpRouterServiceFactory.test.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/backend-defaults/src/entrypoints/httpRouter/httpRouterServiceFactory.test.ts b/packages/backend-defaults/src/entrypoints/httpRouter/httpRouterServiceFactory.test.ts index 58c074f985..2fd6923125 100644 --- a/packages/backend-defaults/src/entrypoints/httpRouter/httpRouterServiceFactory.test.ts +++ b/packages/backend-defaults/src/entrypoints/httpRouter/httpRouterServiceFactory.test.ts @@ -162,6 +162,18 @@ describe('httpRouterFactory', () => { }); }); + it('should always allow the healthcheck endpoint', async () => { + const { server } = await startTestBackend({ + features: [pluginSubject, ...defaultServices], + }); + + await expect( + request(server).get('/api/test/healthcheck'), + ).resolves.toMatchObject({ + status: 200, + }); + }); + it('should not block unauthenticated requests if default policy is disabled', async () => { const { server } = await startTestBackend({ features: [ From 8bbbc314f1d0693f616015301a0b06ba418e7ca5 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Fri, 17 May 2024 11:20:10 +0200 Subject: [PATCH 02/26] backend-app-api: healthcheck middleware Signed-off-by: Vincenzo Scamporlino --- .../httpRouter/createHealthcheck.test.ts | 33 ++++++++++++++++++ .../httpRouter/createHealthcheck.ts | 34 +++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 packages/backend-app-api/src/services/implementations/httpRouter/createHealthcheck.test.ts create mode 100644 packages/backend-app-api/src/services/implementations/httpRouter/createHealthcheck.ts diff --git a/packages/backend-app-api/src/services/implementations/httpRouter/createHealthcheck.test.ts b/packages/backend-app-api/src/services/implementations/httpRouter/createHealthcheck.test.ts new file mode 100644 index 0000000000..c23200a823 --- /dev/null +++ b/packages/backend-app-api/src/services/implementations/httpRouter/createHealthcheck.test.ts @@ -0,0 +1,33 @@ +/* + * Copyright 2024 The Backstage 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. + */ + +import express from 'express'; +import request from 'supertest'; +import { createHealthcheck } from './createHealthcheck'; + +describe('createHealthcheck', () => { + it('should return a router with a healthcheck endpoint', async () => { + const hc = createHealthcheck(); + const app = express().use(hc.router); + + let response = await request(app).get('/healthcheck').expect(200); + expect(response.body).toEqual({ status: 'ok' }); + + hc.addHandler(async () => ({ allgood: true })); + response = await request(app).get('/healthcheck').expect(200); + expect(response.body).toEqual({ allgood: true }); + }); +}); diff --git a/packages/backend-app-api/src/services/implementations/httpRouter/createHealthcheck.ts b/packages/backend-app-api/src/services/implementations/httpRouter/createHealthcheck.ts new file mode 100644 index 0000000000..f177822a17 --- /dev/null +++ b/packages/backend-app-api/src/services/implementations/httpRouter/createHealthcheck.ts @@ -0,0 +1,34 @@ +/* + * Copyright 2024 The Backstage 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. + */ +import { Request, Response } from 'express'; +import Router from 'express-promise-router'; + +export function createHealthcheck() { + const router = Router(); + let handler = () => Promise.resolve({ status: 'ok' }); + + router.get('/healthcheck', async (_request: Request, response: Response) => { + const status = await handler(); + response.json(status); + }); + + return { + router, + addHandler: (newHandler: () => Promise) => { + handler = newHandler; + }, + }; +} From 14e982e8d3fa699196c94d392484f581cd426d5d Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Fri, 17 May 2024 11:34:55 +0200 Subject: [PATCH 03/26] backend-plugin-api: export healthCheckConfig fn Signed-off-by: Vincenzo Scamporlino --- .../src/services/definitions/HttpRouterService.ts | 7 +++++++ .../backend-plugin-api/src/services/definitions/index.ts | 1 + .../backend-test-utils/src/next/services/mockServices.ts | 1 + 3 files changed, 9 insertions(+) diff --git a/packages/backend-plugin-api/src/services/definitions/HttpRouterService.ts b/packages/backend-plugin-api/src/services/definitions/HttpRouterService.ts index 92f7e950f9..2cb5c74649 100644 --- a/packages/backend-plugin-api/src/services/definitions/HttpRouterService.ts +++ b/packages/backend-plugin-api/src/services/definitions/HttpRouterService.ts @@ -26,6 +26,11 @@ export interface HttpRouterServiceAuthPolicy { allow: 'unauthenticated' | 'user-cookie'; } +/** @public */ +export interface HttpRouterHealthCheckConfig { + handler: () => Promise; +} + /** * Allows plugins to register HTTP routes. * @@ -40,6 +45,8 @@ export interface HttpRouterService { */ use(handler: Handler): void; + healthCheckConfig(healthCheckOptions: HttpRouterHealthCheckConfig): void; + /** * Adds an auth policy to the router. This is used to allow unauthenticated or * cookie based access to parts of a plugin's API. diff --git a/packages/backend-plugin-api/src/services/definitions/index.ts b/packages/backend-plugin-api/src/services/definitions/index.ts index 6f30c5f980..57cfd404c1 100644 --- a/packages/backend-plugin-api/src/services/definitions/index.ts +++ b/packages/backend-plugin-api/src/services/definitions/index.ts @@ -35,6 +35,7 @@ export type { DiscoveryService } from './DiscoveryService'; export type { HttpRouterService, HttpRouterServiceAuthPolicy, + HttpRouterHealthCheckConfig, } from './HttpRouterService'; export type { HttpAuthService } from './HttpAuthService'; export type { diff --git a/packages/backend-test-utils/src/next/services/mockServices.ts b/packages/backend-test-utils/src/next/services/mockServices.ts index 24571b634c..379e9473ca 100644 --- a/packages/backend-test-utils/src/next/services/mockServices.ts +++ b/packages/backend-test-utils/src/next/services/mockServices.ts @@ -348,6 +348,7 @@ export namespace mockServices { export const factory = httpRouterServiceFactory; export const mock = simpleMock(coreServices.httpRouter, () => ({ use: jest.fn(), + healthCheckConfig: jest.fn(), addAuthPolicy: jest.fn(), })); } From 53ced701dd6f68b956c3c311da9d674befb0b64a Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Fri, 17 May 2024 11:41:37 +0200 Subject: [PATCH 04/26] healthcheck changeset Signed-off-by: Vincenzo Scamporlino --- .changeset/bright-panthers-leave.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changeset/bright-panthers-leave.md diff --git a/.changeset/bright-panthers-leave.md b/.changeset/bright-panthers-leave.md new file mode 100644 index 0000000000..133760cadd --- /dev/null +++ b/.changeset/bright-panthers-leave.md @@ -0,0 +1,7 @@ +--- +'@backstage/backend-plugin-api': patch +'@backstage/backend-test-utils': patch +'@backstage/backend-app-api': patch +--- + +Added a default `/healthcheck` endpoint to the HTTP Router. From 8d4735767dbada61ac99000ec4e126f5d090c292 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Fri, 17 May 2024 15:17:26 +0200 Subject: [PATCH 05/26] backend-app-api: move healthchecks to healthService Signed-off-by: Vincenzo Scamporlino --- .../health/createHealthRouter.test.ts | 81 +++++++++++++++++++ .../health/createHealthRouter.ts | 46 +++++++++++ .../health/healthServiceFactory.ts | 34 ++++++++ .../services/implementations/health/index.ts | 17 ++++ .../createHealthcheck.test.ts | 0 .../createHealthcheck.ts | 0 .../src/services/definitions/HealthService.ts | 20 +++++ .../services/definitions/HttpRouterService.ts | 5 -- .../src/services/definitions/coreServices.ts | 7 ++ .../src/services/definitions/index.ts | 2 +- .../src/next/services/mockServices.ts | 1 - 11 files changed, 206 insertions(+), 7 deletions(-) create mode 100644 packages/backend-app-api/src/services/implementations/health/createHealthRouter.test.ts create mode 100644 packages/backend-app-api/src/services/implementations/health/createHealthRouter.ts create mode 100644 packages/backend-app-api/src/services/implementations/health/healthServiceFactory.ts create mode 100644 packages/backend-app-api/src/services/implementations/health/index.ts rename packages/backend-app-api/src/services/implementations/{httpRouter => rootHttpRouter}/createHealthcheck.test.ts (100%) rename packages/backend-app-api/src/services/implementations/{httpRouter => rootHttpRouter}/createHealthcheck.ts (100%) create mode 100644 packages/backend-plugin-api/src/services/definitions/HealthService.ts diff --git a/packages/backend-app-api/src/services/implementations/health/createHealthRouter.test.ts b/packages/backend-app-api/src/services/implementations/health/createHealthRouter.test.ts new file mode 100644 index 0000000000..f8c51ee08d --- /dev/null +++ b/packages/backend-app-api/src/services/implementations/health/createHealthRouter.test.ts @@ -0,0 +1,81 @@ +/* + * Copyright 2024 The Backstage 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. + */ + +import { mockServices } from '@backstage/backend-test-utils'; +import request from 'supertest'; +import { createHealthRouter } from './createHealthRouter'; +import express from 'express'; + +describe('createHealthRouter', () => { + describe('readiness', () => { + it(`should return a 500 response if the server hasn't started yet`, async () => { + const hc = createHealthRouter({ + lifecycle: mockServices.rootLifecycle.mock(), + }); + const app = express().use(hc); + + const response = await request(app).get('/v1/readiness'); + expect(response.status).toBe(500); + }); + + it('should return 200 if the server has started', async () => { + const lifecycle = mockServices.rootLifecycle.mock(); + let mockServerStartedFn = () => {}; + lifecycle.addStartupHook.mockImplementation( + fn => (mockServerStartedFn = fn), + ); + + const hc = createHealthRouter({ lifecycle }); + const app = express().use(hc); + + mockServerStartedFn(); + const response = await request(app).get('/v1/readiness').expect(200); + expect(response.body).toEqual({ status: 'ok' }); + }); + + it(`should return a 500 response if the server has stopped`, async () => { + const lifecycle = mockServices.rootLifecycle.mock(); + let mockServerStartedFn = () => {}; + let mockServerStoppedFn = () => {}; + lifecycle.addStartupHook.mockImplementation( + fn => (mockServerStartedFn = fn), + ); + lifecycle.addShutdownHook.mockImplementation( + fn => (mockServerStoppedFn = fn), + ); + + const hc = createHealthRouter({ lifecycle }); + const app = express().use(hc); + + mockServerStartedFn(); + mockServerStoppedFn(); + const response = await request(app).get('/v1/readiness'); + expect(response.status).toBe(500); + }); + }); + + describe('liveness', () => { + it('should return 200 if the server has started', async () => { + const lifecycle = mockServices.rootLifecycle.mock(); + + const hc = createHealthRouter({ lifecycle }); + const app = express().use(hc); + + const response = await request(app).get('/v1/liveness').expect(200); + expect(response.body).toEqual({ status: 'ok' }); + }); + }); +}); diff --git a/packages/backend-app-api/src/services/implementations/health/createHealthRouter.ts b/packages/backend-app-api/src/services/implementations/health/createHealthRouter.ts new file mode 100644 index 0000000000..f2ff2ecd73 --- /dev/null +++ b/packages/backend-app-api/src/services/implementations/health/createHealthRouter.ts @@ -0,0 +1,46 @@ +/* + * Copyright 2024 The Backstage 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. + */ + +import Router from 'express-promise-router'; +import { Request, Response } from 'express'; +import { RootLifecycleService } from '@backstage/backend-plugin-api'; + +export function createHealthRouter(options: { + lifecycle: RootLifecycleService; +}) { + const router = Router(); + + let isRunning = false; + options.lifecycle.addStartupHook(() => { + isRunning = true; + }); + options.lifecycle.addShutdownHook(() => { + isRunning = false; + }); + + router.get('/v1/readiness', async (_request: Request, response: Response) => { + if (!isRunning) { + throw new Error('Backend has not started yet'); + } + response.json({ status: 'ok' }); + }); + + router.get('/v1/liveness', async (_request: Request, response: Response) => { + response.json({ status: 'ok' }); + }); + + return router; +} diff --git a/packages/backend-app-api/src/services/implementations/health/healthServiceFactory.ts b/packages/backend-app-api/src/services/implementations/health/healthServiceFactory.ts new file mode 100644 index 0000000000..831f4fa6e8 --- /dev/null +++ b/packages/backend-app-api/src/services/implementations/health/healthServiceFactory.ts @@ -0,0 +1,34 @@ +/* + * Copyright 2024 The Backstage 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. + */ + +import { + coreServices, + createServiceFactory, +} from '@backstage/backend-plugin-api'; +import { createHealthRouter } from './createHealthRouter'; + +export const healthServiceFactory = createServiceFactory({ + service: coreServices.health, + deps: { + rootHttpRouter: coreServices.rootHttpRouter, + lifecycle: coreServices.rootLifecycle, + }, + async factory({ lifecycle, rootHttpRouter }) { + rootHttpRouter.use('.backstage/health', createHealthRouter({ lifecycle })); + + return {}; + }, +}); diff --git a/packages/backend-app-api/src/services/implementations/health/index.ts b/packages/backend-app-api/src/services/implementations/health/index.ts new file mode 100644 index 0000000000..4aeb4b7979 --- /dev/null +++ b/packages/backend-app-api/src/services/implementations/health/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2024 The Backstage 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. + */ + +export { healthServiceFactory } from './healthServiceFactory'; diff --git a/packages/backend-app-api/src/services/implementations/httpRouter/createHealthcheck.test.ts b/packages/backend-app-api/src/services/implementations/rootHttpRouter/createHealthcheck.test.ts similarity index 100% rename from packages/backend-app-api/src/services/implementations/httpRouter/createHealthcheck.test.ts rename to packages/backend-app-api/src/services/implementations/rootHttpRouter/createHealthcheck.test.ts diff --git a/packages/backend-app-api/src/services/implementations/httpRouter/createHealthcheck.ts b/packages/backend-app-api/src/services/implementations/rootHttpRouter/createHealthcheck.ts similarity index 100% rename from packages/backend-app-api/src/services/implementations/httpRouter/createHealthcheck.ts rename to packages/backend-app-api/src/services/implementations/rootHttpRouter/createHealthcheck.ts diff --git a/packages/backend-plugin-api/src/services/definitions/HealthService.ts b/packages/backend-plugin-api/src/services/definitions/HealthService.ts new file mode 100644 index 0000000000..d04a8a6133 --- /dev/null +++ b/packages/backend-plugin-api/src/services/definitions/HealthService.ts @@ -0,0 +1,20 @@ +/* + * Copyright 2024 The Backstage 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. + */ + +/** + * @public + */ +export interface HealthService {} diff --git a/packages/backend-plugin-api/src/services/definitions/HttpRouterService.ts b/packages/backend-plugin-api/src/services/definitions/HttpRouterService.ts index 2cb5c74649..30c4fb31c8 100644 --- a/packages/backend-plugin-api/src/services/definitions/HttpRouterService.ts +++ b/packages/backend-plugin-api/src/services/definitions/HttpRouterService.ts @@ -26,11 +26,6 @@ export interface HttpRouterServiceAuthPolicy { allow: 'unauthenticated' | 'user-cookie'; } -/** @public */ -export interface HttpRouterHealthCheckConfig { - handler: () => Promise; -} - /** * Allows plugins to register HTTP routes. * diff --git a/packages/backend-plugin-api/src/services/definitions/coreServices.ts b/packages/backend-plugin-api/src/services/definitions/coreServices.ts index b0518fb9d4..36ec0151c5 100644 --- a/packages/backend-plugin-api/src/services/definitions/coreServices.ts +++ b/packages/backend-plugin-api/src/services/definitions/coreServices.ts @@ -102,6 +102,13 @@ export namespace coreServices { import('./DiscoveryService').DiscoveryService >({ id: 'core.discovery' }); + /** + * The service reference for the plugin scoped {@link RootHealthService}. + */ + export const health = createServiceRef< + import('./RootHealthService').RootHealthService + >({ id: 'core.health', scope: 'root' }); + /** * Authentication of HTTP requests. * diff --git a/packages/backend-plugin-api/src/services/definitions/index.ts b/packages/backend-plugin-api/src/services/definitions/index.ts index 57cfd404c1..af0d991f58 100644 --- a/packages/backend-plugin-api/src/services/definitions/index.ts +++ b/packages/backend-plugin-api/src/services/definitions/index.ts @@ -32,10 +32,10 @@ export type { export type { RootConfigService } from './RootConfigService'; export type { DatabaseService } from './DatabaseService'; export type { DiscoveryService } from './DiscoveryService'; +export type { HealthService } from './HealthService'; export type { HttpRouterService, HttpRouterServiceAuthPolicy, - HttpRouterHealthCheckConfig, } from './HttpRouterService'; export type { HttpAuthService } from './HttpAuthService'; export type { diff --git a/packages/backend-test-utils/src/next/services/mockServices.ts b/packages/backend-test-utils/src/next/services/mockServices.ts index 379e9473ca..24571b634c 100644 --- a/packages/backend-test-utils/src/next/services/mockServices.ts +++ b/packages/backend-test-utils/src/next/services/mockServices.ts @@ -348,7 +348,6 @@ export namespace mockServices { export const factory = httpRouterServiceFactory; export const mock = simpleMock(coreServices.httpRouter, () => ({ use: jest.fn(), - healthCheckConfig: jest.fn(), addAuthPolicy: jest.fn(), })); } From b26877ffc50329ce93bd9a7b3d6f016a6f8cd7c6 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Fri, 17 May 2024 15:18:16 +0200 Subject: [PATCH 06/26] backend-defaults: add healthservice Signed-off-by: Vincenzo Scamporlino --- packages/backend-defaults/src/CreateBackend.ts | 2 ++ .../src/services/definitions/HttpRouterService.ts | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/backend-defaults/src/CreateBackend.ts b/packages/backend-defaults/src/CreateBackend.ts index 9b3fa5d649..453c5fe592 100644 --- a/packages/backend-defaults/src/CreateBackend.ts +++ b/packages/backend-defaults/src/CreateBackend.ts @@ -24,6 +24,7 @@ import { authServiceFactory } from '@backstage/backend-defaults/auth'; import { cacheServiceFactory } from '@backstage/backend-defaults/cache'; import { databaseServiceFactory } from '@backstage/backend-defaults/database'; import { discoveryServiceFactory } from '@backstage/backend-defaults/discovery'; +import { rootHealthServiceFactory } from './entrypoints/rootHealth'; import { httpAuthServiceFactory } from '@backstage/backend-defaults/httpAuth'; import { httpRouterServiceFactory } from '@backstage/backend-defaults/httpRouter'; import { lifecycleServiceFactory } from '@backstage/backend-defaults/lifecycle'; @@ -58,6 +59,7 @@ export const defaultServiceFactories = [ userInfoServiceFactory(), urlReaderServiceFactory(), eventsServiceFactory(), + rootHealthServiceFactory(), ]; /** diff --git a/packages/backend-plugin-api/src/services/definitions/HttpRouterService.ts b/packages/backend-plugin-api/src/services/definitions/HttpRouterService.ts index 30c4fb31c8..92f7e950f9 100644 --- a/packages/backend-plugin-api/src/services/definitions/HttpRouterService.ts +++ b/packages/backend-plugin-api/src/services/definitions/HttpRouterService.ts @@ -40,8 +40,6 @@ export interface HttpRouterService { */ use(handler: Handler): void; - healthCheckConfig(healthCheckOptions: HttpRouterHealthCheckConfig): void; - /** * Adds an auth policy to the router. This is used to allow unauthenticated or * cookie based access to parts of a plugin's API. From 1ce0bb70605a3124af959e83993a24f47b58e26e Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Fri, 17 May 2024 15:20:44 +0200 Subject: [PATCH 07/26] tweak changeset Signed-off-by: Vincenzo Scamporlino --- .changeset/bright-panthers-leave.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.changeset/bright-panthers-leave.md b/.changeset/bright-panthers-leave.md index 133760cadd..acd9764fe6 100644 --- a/.changeset/bright-panthers-leave.md +++ b/.changeset/bright-panthers-leave.md @@ -1,7 +1,7 @@ --- '@backstage/backend-plugin-api': patch -'@backstage/backend-test-utils': patch +'@backstage/backend-defaults': patch '@backstage/backend-app-api': patch --- -Added a default `/healthcheck` endpoint to the HTTP Router. +Added a new health service which adds new endpoints for health checks. From 0717aaeda6098f7f3e72f7bb721ec8e38f7062d1 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Fri, 17 May 2024 19:18:06 +0200 Subject: [PATCH 08/26] backend-app-api: remove test Signed-off-by: Vincenzo Scamporlino --- .../httpRouter/httpRouterServiceFactory.test.ts | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/packages/backend-defaults/src/entrypoints/httpRouter/httpRouterServiceFactory.test.ts b/packages/backend-defaults/src/entrypoints/httpRouter/httpRouterServiceFactory.test.ts index 2fd6923125..58c074f985 100644 --- a/packages/backend-defaults/src/entrypoints/httpRouter/httpRouterServiceFactory.test.ts +++ b/packages/backend-defaults/src/entrypoints/httpRouter/httpRouterServiceFactory.test.ts @@ -162,18 +162,6 @@ describe('httpRouterFactory', () => { }); }); - it('should always allow the healthcheck endpoint', async () => { - const { server } = await startTestBackend({ - features: [pluginSubject, ...defaultServices], - }); - - await expect( - request(server).get('/api/test/healthcheck'), - ).resolves.toMatchObject({ - status: 200, - }); - }); - it('should not block unauthenticated requests if default policy is disabled', async () => { const { server } = await startTestBackend({ features: [ From 49b489088cd9f7e262949c21599001c918349dd6 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Fri, 17 May 2024 20:20:44 +0200 Subject: [PATCH 09/26] backend-app-api: mark healthServiceFactory as public Signed-off-by: Vincenzo Scamporlino --- packages/backend-app-api/api-report.md | 4 ++++ .../services/implementations/health/healthServiceFactory.ts | 3 +++ 2 files changed, 7 insertions(+) diff --git a/packages/backend-app-api/api-report.md b/packages/backend-app-api/api-report.md index 7518f8e2cc..a18f027273 100644 --- a/packages/backend-app-api/api-report.md +++ b/packages/backend-app-api/api-report.md @@ -18,6 +18,7 @@ import { ErrorRequestHandler } from 'express'; import { Express as Express_2 } from 'express'; import { Format } from 'logform'; import { Handler } from 'express'; +import { HealthService } from '@backstage/backend-plugin-api'; import { HelmetOptions } from 'helmet'; import * as http from 'http'; import { HttpAuthService } from '@backstage/backend-plugin-api'; @@ -126,6 +127,9 @@ export const discoveryServiceFactory: () => ServiceFactory< // @public @deprecated (undocumented) export type ExtendedHttpServer = ExtendedHttpServer_2; +// @public (undocumented) +export const healthServiceFactory: () => ServiceFactory; + // @public @deprecated export class HostDiscovery implements DiscoveryService { static fromConfig( diff --git a/packages/backend-app-api/src/services/implementations/health/healthServiceFactory.ts b/packages/backend-app-api/src/services/implementations/health/healthServiceFactory.ts index 831f4fa6e8..b79ba34a87 100644 --- a/packages/backend-app-api/src/services/implementations/health/healthServiceFactory.ts +++ b/packages/backend-app-api/src/services/implementations/health/healthServiceFactory.ts @@ -20,6 +20,9 @@ import { } from '@backstage/backend-plugin-api'; import { createHealthRouter } from './createHealthRouter'; +/** + * @public + */ export const healthServiceFactory = createServiceFactory({ service: coreServices.health, deps: { From a38ffb2cb3a72d80027e3293efa74fbd13212a6a Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Mon, 3 Jun 2024 13:33:38 +0200 Subject: [PATCH 10/26] backend-test-utils: mock health service Signed-off-by: Vincenzo Scamporlino --- .../backend-test-utils/src/next/services/mockServices.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/backend-test-utils/src/next/services/mockServices.ts b/packages/backend-test-utils/src/next/services/mockServices.ts index 24571b634c..22496bd6e1 100644 --- a/packages/backend-test-utils/src/next/services/mockServices.ts +++ b/packages/backend-test-utils/src/next/services/mockServices.ts @@ -24,6 +24,7 @@ import { httpRouterServiceFactory } from '@backstage/backend-defaults/httpRouter import { lifecycleServiceFactory } from '@backstage/backend-defaults/lifecycle'; import { loggerServiceFactory } from '@backstage/backend-defaults/logger'; import { permissionsServiceFactory } from '@backstage/backend-defaults/permissions'; +import { rootHealthServiceFactory } from '@backstage/backend-defaults/rootHealth'; import { rootHttpRouterServiceFactory } from '@backstage/backend-defaults/rootHttpRouter'; import { rootLifecycleServiceFactory } from '@backstage/backend-defaults/rootLifecycle'; import { schedulerServiceFactory } from '@backstage/backend-defaults/scheduler'; @@ -383,6 +384,14 @@ export namespace mockServices { })); } + export namespace rootHealth { + export const factory = rootHealthServiceFactory; + export const mock = simpleMock(coreServices.health, () => ({ + getLiveness: jest.fn(), + getReadiness: jest.fn(), + })); + } + export namespace rootLifecycle { export const factory = rootLifecycleServiceFactory; export const mock = simpleMock(coreServices.rootLifecycle, () => ({ From 972896d192834f5ff2d0c115bb6513f758a13829 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Mon, 3 Jun 2024 13:33:54 +0200 Subject: [PATCH 11/26] backend-app-api: clean up Signed-off-by: Vincenzo Scamporlino --- .../rootHttpRouter/createHealthcheck.test.ts | 33 ------------------ .../rootHttpRouter/createHealthcheck.ts | 34 ------------------- 2 files changed, 67 deletions(-) delete mode 100644 packages/backend-app-api/src/services/implementations/rootHttpRouter/createHealthcheck.test.ts delete mode 100644 packages/backend-app-api/src/services/implementations/rootHttpRouter/createHealthcheck.ts diff --git a/packages/backend-app-api/src/services/implementations/rootHttpRouter/createHealthcheck.test.ts b/packages/backend-app-api/src/services/implementations/rootHttpRouter/createHealthcheck.test.ts deleted file mode 100644 index c23200a823..0000000000 --- a/packages/backend-app-api/src/services/implementations/rootHttpRouter/createHealthcheck.test.ts +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2024 The Backstage 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. - */ - -import express from 'express'; -import request from 'supertest'; -import { createHealthcheck } from './createHealthcheck'; - -describe('createHealthcheck', () => { - it('should return a router with a healthcheck endpoint', async () => { - const hc = createHealthcheck(); - const app = express().use(hc.router); - - let response = await request(app).get('/healthcheck').expect(200); - expect(response.body).toEqual({ status: 'ok' }); - - hc.addHandler(async () => ({ allgood: true })); - response = await request(app).get('/healthcheck').expect(200); - expect(response.body).toEqual({ allgood: true }); - }); -}); diff --git a/packages/backend-app-api/src/services/implementations/rootHttpRouter/createHealthcheck.ts b/packages/backend-app-api/src/services/implementations/rootHttpRouter/createHealthcheck.ts deleted file mode 100644 index f177822a17..0000000000 --- a/packages/backend-app-api/src/services/implementations/rootHttpRouter/createHealthcheck.ts +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2024 The Backstage 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. - */ -import { Request, Response } from 'express'; -import Router from 'express-promise-router'; - -export function createHealthcheck() { - const router = Router(); - let handler = () => Promise.resolve({ status: 'ok' }); - - router.get('/healthcheck', async (_request: Request, response: Response) => { - const status = await handler(); - response.json(status); - }); - - return { - router, - addHandler: (newHandler: () => Promise) => { - handler = newHandler; - }, - }; -} From 652da2e3e342994f72639754cafba858dc1d0a94 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Mon, 3 Jun 2024 13:45:41 +0200 Subject: [PATCH 12/26] docs: add health service Signed-off-by: Vincenzo Scamporlino --- docs/backend-system/core-services/01-index.md | 1 + docs/backend-system/core-services/health.md | 39 +++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 docs/backend-system/core-services/health.md diff --git a/docs/backend-system/core-services/01-index.md b/docs/backend-system/core-services/01-index.md index 04d2e57ae8..63324292c1 100644 --- a/docs/backend-system/core-services/01-index.md +++ b/docs/backend-system/core-services/01-index.md @@ -20,6 +20,7 @@ import { coreServices } from '@backstage/backend-plugin-api'; - [Cache Service](./cache.md) - Key-value store for caching data. - [Database Service](./database.md) - Database access and management via [knex](https://knexjs.org/). - [Discovery Service](./discovery.md) - Service discovery for inter-plugin communication. +- [Health Service](./health.md) - Health check endpoints for the backend. - [Http Auth Service](./http-auth.md) - Authentication of HTTP requests. - [Http Router Service](./http-router.md) - HTTP route registration for plugins. - [Identity Service](./identity.md) - Deprecated user authentication service, use the [Auth Service](./auth.md) instead. diff --git a/docs/backend-system/core-services/health.md b/docs/backend-system/core-services/health.md new file mode 100644 index 0000000000..9a69891624 --- /dev/null +++ b/docs/backend-system/core-services/health.md @@ -0,0 +1,39 @@ +--- +id: health +title: Heath Service +sidebar_label: Health +description: Documentation for the Health service +--- + +The Health service provides some health check endpoints for the plugins. By default, it attaches `/.backstage/health/v1/readiness` and `/.backstage/health/v1/liveness` endpoints to the backend server, which return a JSON object with the status of the backend services. + +## Configuring the service + +The following example is how you can override the health service to add custom endpoints. + +```ts +import { coreServices } from '@backstage/backend-plugin-api'; +import { WinstonLogger } from '@backstage/backend-app-api'; + +const backend = createBackend(); + +backend.add( + createServiceFactory({ + service: coreServices.health, + deps: { + rootHttpRouter: coreServices.rootHttpRouter, + }, + async factory({ rootHttpRouter }) { + rootHttpRouter.get('.backstage/health/v1/readiness', async (req, res) => { + res.json({ status: 'ok' }); + }); + + rootHttpRouter.get('.backstage/health/v1/liveness', async (req, res) => { + res.json({ status: 'ok' }); + }); + + return {}; + }, + }), +); +``` From 78fdc5a39f613a50f6a024b68a9abb1201396d78 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Mon, 3 Jun 2024 14:11:33 +0200 Subject: [PATCH 13/26] health service api report Signed-off-by: Vincenzo Scamporlino --- packages/backend-plugin-api/api-report.md | 4 ++++ packages/backend-test-utils/api-report.md | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/packages/backend-plugin-api/api-report.md b/packages/backend-plugin-api/api-report.md index 258cdefe1b..5e02ad1787 100644 --- a/packages/backend-plugin-api/api-report.md +++ b/packages/backend-plugin-api/api-report.md @@ -194,6 +194,7 @@ export namespace coreServices { const rootConfig: ServiceRef; const database: ServiceRef; const discovery: ServiceRef; + const health: ServiceRef; const httpAuth: ServiceRef; const httpRouter: ServiceRef; const lifecycle: ServiceRef; @@ -333,6 +334,9 @@ export type ExtensionPoint = { // @public @deprecated (undocumented) export type ExtensionPointConfig = CreateExtensionPointOptions; +// @public (undocumented) +export interface HealthService {} + // @public export interface HttpAuthService { credentials( diff --git a/packages/backend-test-utils/api-report.md b/packages/backend-test-utils/api-report.md index 019d398ea6..07b393b653 100644 --- a/packages/backend-test-utils/api-report.md +++ b/packages/backend-test-utils/api-report.md @@ -21,6 +21,7 @@ import { DiscoveryService } from '@backstage/backend-plugin-api'; import { EventsService } from '@backstage/plugin-events-node'; import { ExtendedHttpServer } from '@backstage/backend-app-api'; import { ExtensionPoint } from '@backstage/backend-plugin-api'; +import { HealthService } from '@backstage/backend-plugin-api'; import { HttpAuthService } from '@backstage/backend-plugin-api'; import { HttpRouterFactoryOptions } from '@backstage/backend-defaults/httpRouter'; import { HttpRouterService } from '@backstage/backend-plugin-api'; @@ -199,6 +200,15 @@ export namespace mockServices { partialImpl?: Partial | undefined, ) => ServiceMock; } + // (undocumented) + export namespace health { + const // (undocumented) + factory: () => ServiceFactory; + const // (undocumented) + mock: ( + partialImpl?: Partial | undefined, + ) => ServiceMock; + } export function httpAuth(options?: { pluginId?: string; defaultCredentials?: BackstageCredentials; From fce7887109d2741e896b0c2d25303999db42760c Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Mon, 3 Jun 2024 14:18:11 +0200 Subject: [PATCH 14/26] backend-test-utils: health service mock changeset Signed-off-by: Vincenzo Scamporlino --- .changeset/serious-kings-trade.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/serious-kings-trade.md diff --git a/.changeset/serious-kings-trade.md b/.changeset/serious-kings-trade.md new file mode 100644 index 0000000000..c07e92b88a --- /dev/null +++ b/.changeset/serious-kings-trade.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-test-utils': patch +--- + +Added mock for health service in `mockServices`. From 918b397763b17f70bab8494bd7b87ddeb084d1b2 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Wed, 5 Jun 2024 13:27:10 +0200 Subject: [PATCH 15/26] backend-defaults: move over health service Signed-off-by: Vincenzo Scamporlino --- .../health/createHealthRouter.ts | 46 -------------- .../health/healthServiceFactory.ts | 37 ----------- .../backend-defaults/api-report-health.md | 13 ++++ packages/backend-defaults/package.json | 4 ++ .../health/healthServiceFactory.test.ts} | 53 ++++++++-------- .../health/healthServiceFactory.ts | 63 +++++++++++++++++++ .../src/entrypoints}/health/index.ts | 0 7 files changed, 107 insertions(+), 109 deletions(-) delete mode 100644 packages/backend-app-api/src/services/implementations/health/createHealthRouter.ts delete mode 100644 packages/backend-app-api/src/services/implementations/health/healthServiceFactory.ts create mode 100644 packages/backend-defaults/api-report-health.md rename packages/{backend-app-api/src/services/implementations/health/createHealthRouter.test.ts => backend-defaults/src/entrypoints/health/healthServiceFactory.test.ts} (63%) create mode 100644 packages/backend-defaults/src/entrypoints/health/healthServiceFactory.ts rename packages/{backend-app-api/src/services/implementations => backend-defaults/src/entrypoints}/health/index.ts (100%) diff --git a/packages/backend-app-api/src/services/implementations/health/createHealthRouter.ts b/packages/backend-app-api/src/services/implementations/health/createHealthRouter.ts deleted file mode 100644 index f2ff2ecd73..0000000000 --- a/packages/backend-app-api/src/services/implementations/health/createHealthRouter.ts +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2024 The Backstage 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. - */ - -import Router from 'express-promise-router'; -import { Request, Response } from 'express'; -import { RootLifecycleService } from '@backstage/backend-plugin-api'; - -export function createHealthRouter(options: { - lifecycle: RootLifecycleService; -}) { - const router = Router(); - - let isRunning = false; - options.lifecycle.addStartupHook(() => { - isRunning = true; - }); - options.lifecycle.addShutdownHook(() => { - isRunning = false; - }); - - router.get('/v1/readiness', async (_request: Request, response: Response) => { - if (!isRunning) { - throw new Error('Backend has not started yet'); - } - response.json({ status: 'ok' }); - }); - - router.get('/v1/liveness', async (_request: Request, response: Response) => { - response.json({ status: 'ok' }); - }); - - return router; -} diff --git a/packages/backend-app-api/src/services/implementations/health/healthServiceFactory.ts b/packages/backend-app-api/src/services/implementations/health/healthServiceFactory.ts deleted file mode 100644 index b79ba34a87..0000000000 --- a/packages/backend-app-api/src/services/implementations/health/healthServiceFactory.ts +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2024 The Backstage 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. - */ - -import { - coreServices, - createServiceFactory, -} from '@backstage/backend-plugin-api'; -import { createHealthRouter } from './createHealthRouter'; - -/** - * @public - */ -export const healthServiceFactory = createServiceFactory({ - service: coreServices.health, - deps: { - rootHttpRouter: coreServices.rootHttpRouter, - lifecycle: coreServices.rootLifecycle, - }, - async factory({ lifecycle, rootHttpRouter }) { - rootHttpRouter.use('.backstage/health', createHealthRouter({ lifecycle })); - - return {}; - }, -}); diff --git a/packages/backend-defaults/api-report-health.md b/packages/backend-defaults/api-report-health.md new file mode 100644 index 0000000000..795bdaac78 --- /dev/null +++ b/packages/backend-defaults/api-report-health.md @@ -0,0 +1,13 @@ +## API Report File for "@backstage/backend-defaults" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { HealthService } from '@backstage/backend-plugin-api'; +import { ServiceFactory } from '@backstage/backend-plugin-api'; + +// @public (undocumented) +export const healthServiceFactory: () => ServiceFactory; + +// (No @packageDocumentation comment for this package) +``` diff --git a/packages/backend-defaults/package.json b/packages/backend-defaults/package.json index 4c34c7f317..c29d973997 100644 --- a/packages/backend-defaults/package.json +++ b/packages/backend-defaults/package.json @@ -24,6 +24,7 @@ "./cache": "./src/entrypoints/cache/index.ts", "./database": "./src/entrypoints/database/index.ts", "./discovery": "./src/entrypoints/discovery/index.ts", + "./health": "./src/entrypoints/health/index.ts", "./httpAuth": "./src/entrypoints/httpAuth/index.ts", "./httpRouter": "./src/entrypoints/httpRouter/index.ts", "./lifecycle": "./src/entrypoints/lifecycle/index.ts", @@ -54,6 +55,9 @@ "discovery": [ "src/entrypoints/discovery/index.ts" ], + "health": [ + "src/entrypoints/health/index.ts" + ], "httpAuth": [ "src/entrypoints/httpAuth/index.ts" ], diff --git a/packages/backend-app-api/src/services/implementations/health/createHealthRouter.test.ts b/packages/backend-defaults/src/entrypoints/health/healthServiceFactory.test.ts similarity index 63% rename from packages/backend-app-api/src/services/implementations/health/createHealthRouter.test.ts rename to packages/backend-defaults/src/entrypoints/health/healthServiceFactory.test.ts index f8c51ee08d..40a41d74f5 100644 --- a/packages/backend-app-api/src/services/implementations/health/createHealthRouter.test.ts +++ b/packages/backend-defaults/src/entrypoints/health/healthServiceFactory.test.ts @@ -1,3 +1,6 @@ +import { mockServices } from '@backstage/backend-test-utils'; +import { DefaultHealthService } from './healthServiceFactory'; + /* * Copyright 2024 The Backstage Authors * @@ -13,22 +16,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -import { mockServices } from '@backstage/backend-test-utils'; -import request from 'supertest'; -import { createHealthRouter } from './createHealthRouter'; -import express from 'express'; - -describe('createHealthRouter', () => { +describe('DefaultHealthService', () => { describe('readiness', () => { it(`should return a 500 response if the server hasn't started yet`, async () => { - const hc = createHealthRouter({ + const service = new DefaultHealthService({ lifecycle: mockServices.rootLifecycle.mock(), }); - const app = express().use(hc); - - const response = await request(app).get('/v1/readiness'); - expect(response.status).toBe(500); + await expect(service.getReadiness()).resolves.toEqual({ status: 503 }); }); it('should return 200 if the server has started', async () => { @@ -38,12 +32,16 @@ describe('createHealthRouter', () => { fn => (mockServerStartedFn = fn), ); - const hc = createHealthRouter({ lifecycle }); - const app = express().use(hc); + const service = new DefaultHealthService({ + lifecycle: mockServices.rootLifecycle.mock(), + }); mockServerStartedFn(); - const response = await request(app).get('/v1/readiness').expect(200); - expect(response.body).toEqual({ status: 'ok' }); + + await expect(service.getReadiness()).resolves.toEqual({ + status: 200, + payload: { status: 'ok' }, + }); }); it(`should return a 500 response if the server has stopped`, async () => { @@ -57,25 +55,28 @@ describe('createHealthRouter', () => { fn => (mockServerStoppedFn = fn), ); - const hc = createHealthRouter({ lifecycle }); - const app = express().use(hc); + const service = new DefaultHealthService({ + lifecycle: mockServices.rootLifecycle.mock(), + }); mockServerStartedFn(); mockServerStoppedFn(); - const response = await request(app).get('/v1/readiness'); - expect(response.status).toBe(500); + await expect(service.getReadiness()).resolves.toEqual({ + status: 503, + }); }); }); describe('liveness', () => { it('should return 200 if the server has started', async () => { - const lifecycle = mockServices.rootLifecycle.mock(); + const service = new DefaultHealthService({ + lifecycle: mockServices.rootLifecycle.mock(), + }); - const hc = createHealthRouter({ lifecycle }); - const app = express().use(hc); - - const response = await request(app).get('/v1/liveness').expect(200); - expect(response.body).toEqual({ status: 'ok' }); + await expect(service.getLiveness()).resolves.toEqual({ + status: 200, + payload: { status: 'ok' }, + }); }); }); }); diff --git a/packages/backend-defaults/src/entrypoints/health/healthServiceFactory.ts b/packages/backend-defaults/src/entrypoints/health/healthServiceFactory.ts new file mode 100644 index 0000000000..3f397ce29b --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/health/healthServiceFactory.ts @@ -0,0 +1,63 @@ +import { + HealthService, + RootLifecycleService, + coreServices, + createServiceFactory, +} from '@backstage/backend-plugin-api'; + +/* + * Copyright 2024 The Backstage 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. + */ + +/** @internal */ +export class DefaultHealthService implements HealthService { + #isRunning = false; + + constructor(readonly options: { lifecycle: RootLifecycleService }) { + options.lifecycle.addStartupHook(() => { + this.#isRunning = true; + }); + options.lifecycle.addShutdownHook(() => { + this.#isRunning = false; + }); + } + + async getLiveness(): Promise<{ status: number; payload?: any }> { + return { status: 200, payload: { status: 'ok' } }; + } + async getReadiness(): Promise<{ status: number; payload?: any }> { + if (!this.#isRunning) { + return { + status: 503, + payload: { message: 'Backend has not started yet', status: 'error' }, + }; + } + + return { status: 200, payload: { status: 'ok' } }; + } +} + +/** + * @public + */ +export const healthServiceFactory = createServiceFactory({ + service: coreServices.health, + deps: { + lifecycle: coreServices.rootLifecycle, + }, + async factory({ lifecycle }) { + return new DefaultHealthService({ lifecycle }); + }, +}); diff --git a/packages/backend-app-api/src/services/implementations/health/index.ts b/packages/backend-defaults/src/entrypoints/health/index.ts similarity index 100% rename from packages/backend-app-api/src/services/implementations/health/index.ts rename to packages/backend-defaults/src/entrypoints/health/index.ts From 44f97c173bf9eefb3c281928b84aa1f80bc32375 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Wed, 5 Jun 2024 13:27:39 +0200 Subject: [PATCH 16/26] backend-app-api: flip logic of health service Signed-off-by: Vincenzo Scamporlino --- .../health/healthServiceFactory.test.ts | 14 ++++++- .../health/healthServiceFactory.ts | 1 + .../rootHttpRouter/createHealthRouter.ts | 42 +++++++++++++++++++ .../rootHttpRouterServiceFactory.ts | 9 +++- packages/backend-plugin-api/api-report.md | 13 +++++- .../src/services/definitions/HealthService.ts | 5 ++- .../src/next/services/mockServices.ts | 18 ++++---- 7 files changed, 88 insertions(+), 14 deletions(-) create mode 100644 packages/backend-defaults/src/entrypoints/rootHttpRouter/createHealthRouter.ts diff --git a/packages/backend-defaults/src/entrypoints/health/healthServiceFactory.test.ts b/packages/backend-defaults/src/entrypoints/health/healthServiceFactory.test.ts index 40a41d74f5..7e160cbd82 100644 --- a/packages/backend-defaults/src/entrypoints/health/healthServiceFactory.test.ts +++ b/packages/backend-defaults/src/entrypoints/health/healthServiceFactory.test.ts @@ -22,7 +22,13 @@ describe('DefaultHealthService', () => { const service = new DefaultHealthService({ lifecycle: mockServices.rootLifecycle.mock(), }); - await expect(service.getReadiness()).resolves.toEqual({ status: 503 }); + await expect(service.getReadiness()).resolves.toEqual({ + status: 503, + payload: { + message: 'Backend has not started yet', + status: 'error', + }, + }); }); it('should return 200 if the server has started', async () => { @@ -33,7 +39,7 @@ describe('DefaultHealthService', () => { ); const service = new DefaultHealthService({ - lifecycle: mockServices.rootLifecycle.mock(), + lifecycle, }); mockServerStartedFn(); @@ -63,6 +69,10 @@ describe('DefaultHealthService', () => { mockServerStoppedFn(); await expect(service.getReadiness()).resolves.toEqual({ status: 503, + payload: { + message: 'Backend has not started yet', + status: 'error', + }, }); }); }); diff --git a/packages/backend-defaults/src/entrypoints/health/healthServiceFactory.ts b/packages/backend-defaults/src/entrypoints/health/healthServiceFactory.ts index 3f397ce29b..f68451df74 100644 --- a/packages/backend-defaults/src/entrypoints/health/healthServiceFactory.ts +++ b/packages/backend-defaults/src/entrypoints/health/healthServiceFactory.ts @@ -37,6 +37,7 @@ export class DefaultHealthService implements HealthService { async getLiveness(): Promise<{ status: number; payload?: any }> { return { status: 200, payload: { status: 'ok' } }; } + async getReadiness(): Promise<{ status: number; payload?: any }> { if (!this.#isRunning) { return { diff --git a/packages/backend-defaults/src/entrypoints/rootHttpRouter/createHealthRouter.ts b/packages/backend-defaults/src/entrypoints/rootHttpRouter/createHealthRouter.ts new file mode 100644 index 0000000000..012a268e02 --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/rootHttpRouter/createHealthRouter.ts @@ -0,0 +1,42 @@ +import { HealthService } from '@backstage/backend-plugin-api'; + +/* + * Copyright 2024 The Backstage 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. + */ + +import Router from 'express-promise-router'; +import { Request, Response } from 'express'; + +export function createHealthRouter(options: { health: HealthService }) { + const router = Router(); + + router.get( + '.backstage/health/v1/readiness', + async (_request: Request, response: Response) => { + const { status, payload } = await options.health.getReadiness(); + response.status(status).json(payload); + }, + ); + + router.get( + '.backstage/health/v1/liveness', + async (_request: Request, response: Response) => { + const { status, payload } = await options.health.getLiveness(); + response.status(status).json(payload); + }, + ); + + return router; +} diff --git a/packages/backend-defaults/src/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.ts b/packages/backend-defaults/src/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.ts index ea3dc42eb7..5f22cf5ced 100644 --- a/packages/backend-defaults/src/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.ts +++ b/packages/backend-defaults/src/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.ts @@ -29,6 +29,7 @@ import { readHttpServerOptions, } from './http'; import { DefaultRootHttpRouter } from './DefaultRootHttpRouter'; +import { createHealthRouter } from './createHealthRouter'; /** * @public @@ -41,6 +42,7 @@ export interface RootHttpRouterConfigureContext { config: RootConfigService; logger: LoggerService; lifecycle: LifecycleService; + healthRouter: RequestHandler; applyDefaults: () => void; } @@ -75,8 +77,9 @@ export const rootHttpRouterServiceFactory = createServiceFactory( config: coreServices.rootConfig, rootLogger: coreServices.rootLogger, lifecycle: coreServices.rootLifecycle, + health: coreServices.health, }, - async factory({ config, rootLogger, lifecycle }) { + async factory({ config, rootLogger, lifecycle, health }) { const { indexPath, configure = defaultConfigure } = options ?? {}; const logger = rootLogger.child({ service: 'rootHttpRouter' }); const app = express(); @@ -84,6 +87,8 @@ export const rootHttpRouterServiceFactory = createServiceFactory( const router = DefaultRootHttpRouter.create({ indexPath }); const middleware = MiddlewareFactory.create({ config, logger }); const routes = router.handler(); + + const healthRouter = createHealthRouter({ health }); const server = await createHttpServer( app, readHttpServerOptions(config.getOptionalConfig('backend')), @@ -98,11 +103,13 @@ export const rootHttpRouterServiceFactory = createServiceFactory( config, logger, lifecycle, + healthRouter, applyDefaults() { app.use(middleware.helmet()); app.use(middleware.cors()); app.use(middleware.compression()); app.use(middleware.logging()); + app.use(healthRouter); app.use(routes); app.use(middleware.notFound()); app.use(middleware.error()); diff --git a/packages/backend-plugin-api/api-report.md b/packages/backend-plugin-api/api-report.md index 5e02ad1787..ee5aecd63b 100644 --- a/packages/backend-plugin-api/api-report.md +++ b/packages/backend-plugin-api/api-report.md @@ -335,7 +335,18 @@ export type ExtensionPoint = { export type ExtensionPointConfig = CreateExtensionPointOptions; // @public (undocumented) -export interface HealthService {} +export interface HealthService { + // (undocumented) + getLiveness(): Promise<{ + status: number; + payload?: any; + }>; + // (undocumented) + getReadiness(): Promise<{ + status: number; + payload?: any; + }>; +} // @public export interface HttpAuthService { diff --git a/packages/backend-plugin-api/src/services/definitions/HealthService.ts b/packages/backend-plugin-api/src/services/definitions/HealthService.ts index d04a8a6133..b2dc4f415e 100644 --- a/packages/backend-plugin-api/src/services/definitions/HealthService.ts +++ b/packages/backend-plugin-api/src/services/definitions/HealthService.ts @@ -17,4 +17,7 @@ /** * @public */ -export interface HealthService {} +export interface HealthService { + getLiveness(): Promise<{ status: number; payload?: any }>; + getReadiness(): Promise<{ status: number; payload?: any }>; +} diff --git a/packages/backend-test-utils/src/next/services/mockServices.ts b/packages/backend-test-utils/src/next/services/mockServices.ts index 22496bd6e1..a59d053b95 100644 --- a/packages/backend-test-utils/src/next/services/mockServices.ts +++ b/packages/backend-test-utils/src/next/services/mockServices.ts @@ -20,11 +20,11 @@ import { HostDiscovery, discoveryServiceFactory, } from '@backstage/backend-defaults/discovery'; +import { healthServiceFactory } from '@backstage/backend-defaults/health'; import { httpRouterServiceFactory } from '@backstage/backend-defaults/httpRouter'; import { lifecycleServiceFactory } from '@backstage/backend-defaults/lifecycle'; import { loggerServiceFactory } from '@backstage/backend-defaults/logger'; import { permissionsServiceFactory } from '@backstage/backend-defaults/permissions'; -import { rootHealthServiceFactory } from '@backstage/backend-defaults/rootHealth'; import { rootHttpRouterServiceFactory } from '@backstage/backend-defaults/rootHttpRouter'; import { rootLifecycleServiceFactory } from '@backstage/backend-defaults/rootLifecycle'; import { schedulerServiceFactory } from '@backstage/backend-defaults/scheduler'; @@ -345,6 +345,14 @@ export namespace mockServices { })); } + export namespace health { + export const factory = healthServiceFactory; + export const mock = simpleMock(coreServices.health, () => ({ + getLiveness: jest.fn(), + getReadiness: jest.fn(), + })); + } + export namespace httpRouter { export const factory = httpRouterServiceFactory; export const mock = simpleMock(coreServices.httpRouter, () => ({ @@ -384,14 +392,6 @@ export namespace mockServices { })); } - export namespace rootHealth { - export const factory = rootHealthServiceFactory; - export const mock = simpleMock(coreServices.health, () => ({ - getLiveness: jest.fn(), - getReadiness: jest.fn(), - })); - } - export namespace rootLifecycle { export const factory = rootLifecycleServiceFactory; export const mock = simpleMock(coreServices.rootLifecycle, () => ({ From 506fc235567a02a8609c5859f3311cda393aaa04 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Thu, 13 Jun 2024 13:11:03 +0200 Subject: [PATCH 17/26] backend-defaults: fix notice Signed-off-by: Vincenzo Scamporlino --- .../src/entrypoints/health/healthServiceFactory.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/backend-defaults/src/entrypoints/health/healthServiceFactory.ts b/packages/backend-defaults/src/entrypoints/health/healthServiceFactory.ts index f68451df74..652ad8758f 100644 --- a/packages/backend-defaults/src/entrypoints/health/healthServiceFactory.ts +++ b/packages/backend-defaults/src/entrypoints/health/healthServiceFactory.ts @@ -1,10 +1,3 @@ -import { - HealthService, - RootLifecycleService, - coreServices, - createServiceFactory, -} from '@backstage/backend-plugin-api'; - /* * Copyright 2024 The Backstage Authors * @@ -21,6 +14,13 @@ import { * limitations under the License. */ +import { + HealthService, + RootLifecycleService, + coreServices, + createServiceFactory, +} from '@backstage/backend-plugin-api'; + /** @internal */ export class DefaultHealthService implements HealthService { #isRunning = false; From 0c621514042da57665afc28336be9cfa03fe430d Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Thu, 13 Jun 2024 13:39:33 +0200 Subject: [PATCH 18/26] Rename HealthService to RootHealthService Signed-off-by: Vincenzo Scamporlino --- docs/backend-system/core-services/01-index.md | 2 +- .../core-services/{health.md => root-health.md} | 0 packages/backend-defaults/package.json | 8 ++++---- packages/backend-defaults/src/CreateBackend.ts | 4 ++-- .../src/entrypoints/{health => rootHealth}/index.ts | 2 +- .../rootHealthServiceFactory.test.ts} | 12 ++++++------ .../rootHealthServiceFactory.ts} | 8 ++++---- .../entrypoints/rootHttpRouter/createHealthRouter.ts | 4 ++-- .../{HealthService.ts => RootHealthService.ts} | 8 +++++++- .../src/services/definitions/index.ts | 2 +- .../src/next/services/mockServices.ts | 6 +++--- 11 files changed, 31 insertions(+), 25 deletions(-) rename docs/backend-system/core-services/{health.md => root-health.md} (100%) rename packages/backend-defaults/src/entrypoints/{health => rootHealth}/index.ts (89%) rename packages/backend-defaults/src/entrypoints/{health/healthServiceFactory.test.ts => rootHealth/rootHealthServiceFactory.test.ts} (88%) rename packages/backend-defaults/src/entrypoints/{health/healthServiceFactory.ts => rootHealth/rootHealthServiceFactory.ts} (88%) rename packages/backend-plugin-api/src/services/definitions/{HealthService.ts => RootHealthService.ts} (83%) diff --git a/docs/backend-system/core-services/01-index.md b/docs/backend-system/core-services/01-index.md index 63324292c1..3be12b2e26 100644 --- a/docs/backend-system/core-services/01-index.md +++ b/docs/backend-system/core-services/01-index.md @@ -20,7 +20,6 @@ import { coreServices } from '@backstage/backend-plugin-api'; - [Cache Service](./cache.md) - Key-value store for caching data. - [Database Service](./database.md) - Database access and management via [knex](https://knexjs.org/). - [Discovery Service](./discovery.md) - Service discovery for inter-plugin communication. -- [Health Service](./health.md) - Health check endpoints for the backend. - [Http Auth Service](./http-auth.md) - Authentication of HTTP requests. - [Http Router Service](./http-router.md) - HTTP route registration for plugins. - [Identity Service](./identity.md) - Deprecated user authentication service, use the [Auth Service](./auth.md) instead. @@ -29,6 +28,7 @@ import { coreServices } from '@backstage/backend-plugin-api'; - [Permissions Service](./permissions.md) - Permission system integration for authorization of user actions. - [Plugin Metadata Service](./plugin-metadata.md) - Built-in service for accessing metadata about the current plugin. - [Root Config Service](./root-config.md) - Access to static configuration. +- [Root Health Service](./root-health.md) - Health check endpoints for the backend. - [Root Http Router Service](./root-http-router.md) - HTTP route registration for root services. - [Root Lifecycle Service](./root-lifecycle.md) - Registration of backend startup and shutdown lifecycle hooks. - [Root Logger Service](./root-logger.md) - Root-level logging. diff --git a/docs/backend-system/core-services/health.md b/docs/backend-system/core-services/root-health.md similarity index 100% rename from docs/backend-system/core-services/health.md rename to docs/backend-system/core-services/root-health.md diff --git a/packages/backend-defaults/package.json b/packages/backend-defaults/package.json index c29d973997..2d84bae308 100644 --- a/packages/backend-defaults/package.json +++ b/packages/backend-defaults/package.json @@ -24,13 +24,13 @@ "./cache": "./src/entrypoints/cache/index.ts", "./database": "./src/entrypoints/database/index.ts", "./discovery": "./src/entrypoints/discovery/index.ts", - "./health": "./src/entrypoints/health/index.ts", "./httpAuth": "./src/entrypoints/httpAuth/index.ts", "./httpRouter": "./src/entrypoints/httpRouter/index.ts", "./lifecycle": "./src/entrypoints/lifecycle/index.ts", "./logger": "./src/entrypoints/logger/index.ts", "./permissions": "./src/entrypoints/permissions/index.ts", "./rootConfig": "./src/entrypoints/rootConfig/index.ts", + "./rootHealth": "./src/entrypoints/rootHealth/index.ts", "./rootHttpRouter": "./src/entrypoints/rootHttpRouter/index.ts", "./rootLifecycle": "./src/entrypoints/rootLifecycle/index.ts", "./rootLogger": "./src/entrypoints/rootLogger/index.ts", @@ -55,9 +55,6 @@ "discovery": [ "src/entrypoints/discovery/index.ts" ], - "health": [ - "src/entrypoints/health/index.ts" - ], "httpAuth": [ "src/entrypoints/httpAuth/index.ts" ], @@ -76,6 +73,9 @@ "rootConfig": [ "src/entrypoints/rootConfig/index.ts" ], + "rootHealth": [ + "src/entrypoints/rootHealth/index.ts" + ], "rootHttpRouter": [ "src/entrypoints/rootHttpRouter/index.ts" ], diff --git a/packages/backend-defaults/src/CreateBackend.ts b/packages/backend-defaults/src/CreateBackend.ts index 453c5fe592..e3195748a6 100644 --- a/packages/backend-defaults/src/CreateBackend.ts +++ b/packages/backend-defaults/src/CreateBackend.ts @@ -24,13 +24,13 @@ import { authServiceFactory } from '@backstage/backend-defaults/auth'; import { cacheServiceFactory } from '@backstage/backend-defaults/cache'; import { databaseServiceFactory } from '@backstage/backend-defaults/database'; import { discoveryServiceFactory } from '@backstage/backend-defaults/discovery'; -import { rootHealthServiceFactory } from './entrypoints/rootHealth'; import { httpAuthServiceFactory } from '@backstage/backend-defaults/httpAuth'; import { httpRouterServiceFactory } from '@backstage/backend-defaults/httpRouter'; import { lifecycleServiceFactory } from '@backstage/backend-defaults/lifecycle'; import { loggerServiceFactory } from '@backstage/backend-defaults/logger'; import { permissionsServiceFactory } from '@backstage/backend-defaults/permissions'; import { rootConfigServiceFactory } from '@backstage/backend-defaults/rootConfig'; +import { rootHealthServiceFactory } from '@backstage/backend-defaults/rootHealth'; import { rootHttpRouterServiceFactory } from '@backstage/backend-defaults/rootHttpRouter'; import { rootLifecycleServiceFactory } from '@backstage/backend-defaults/rootLifecycle'; import { rootLoggerServiceFactory } from '@backstage/backend-defaults/rootLogger'; @@ -51,6 +51,7 @@ export const defaultServiceFactories = [ lifecycleServiceFactory(), loggerServiceFactory(), permissionsServiceFactory(), + rootHealthServiceFactory(), rootHttpRouterServiceFactory(), rootLifecycleServiceFactory(), rootLoggerServiceFactory(), @@ -59,7 +60,6 @@ export const defaultServiceFactories = [ userInfoServiceFactory(), urlReaderServiceFactory(), eventsServiceFactory(), - rootHealthServiceFactory(), ]; /** diff --git a/packages/backend-defaults/src/entrypoints/health/index.ts b/packages/backend-defaults/src/entrypoints/rootHealth/index.ts similarity index 89% rename from packages/backend-defaults/src/entrypoints/health/index.ts rename to packages/backend-defaults/src/entrypoints/rootHealth/index.ts index 4aeb4b7979..35225b39c4 100644 --- a/packages/backend-defaults/src/entrypoints/health/index.ts +++ b/packages/backend-defaults/src/entrypoints/rootHealth/index.ts @@ -14,4 +14,4 @@ * limitations under the License. */ -export { healthServiceFactory } from './healthServiceFactory'; +export { rootHealthServiceFactory } from './rootHealthServiceFactory'; diff --git a/packages/backend-defaults/src/entrypoints/health/healthServiceFactory.test.ts b/packages/backend-defaults/src/entrypoints/rootHealth/rootHealthServiceFactory.test.ts similarity index 88% rename from packages/backend-defaults/src/entrypoints/health/healthServiceFactory.test.ts rename to packages/backend-defaults/src/entrypoints/rootHealth/rootHealthServiceFactory.test.ts index 7e160cbd82..fd786e2b28 100644 --- a/packages/backend-defaults/src/entrypoints/health/healthServiceFactory.test.ts +++ b/packages/backend-defaults/src/entrypoints/rootHealth/rootHealthServiceFactory.test.ts @@ -1,5 +1,5 @@ import { mockServices } from '@backstage/backend-test-utils'; -import { DefaultHealthService } from './healthServiceFactory'; +import { DefaultRootHealthService } from './rootHealthServiceFactory'; /* * Copyright 2024 The Backstage Authors @@ -16,10 +16,10 @@ import { DefaultHealthService } from './healthServiceFactory'; * See the License for the specific language governing permissions and * limitations under the License. */ -describe('DefaultHealthService', () => { +describe('DefaultRootHealthService', () => { describe('readiness', () => { it(`should return a 500 response if the server hasn't started yet`, async () => { - const service = new DefaultHealthService({ + const service = new DefaultRootHealthService({ lifecycle: mockServices.rootLifecycle.mock(), }); await expect(service.getReadiness()).resolves.toEqual({ @@ -38,7 +38,7 @@ describe('DefaultHealthService', () => { fn => (mockServerStartedFn = fn), ); - const service = new DefaultHealthService({ + const service = new DefaultRootHealthService({ lifecycle, }); @@ -61,7 +61,7 @@ describe('DefaultHealthService', () => { fn => (mockServerStoppedFn = fn), ); - const service = new DefaultHealthService({ + const service = new DefaultRootHealthService({ lifecycle: mockServices.rootLifecycle.mock(), }); @@ -79,7 +79,7 @@ describe('DefaultHealthService', () => { describe('liveness', () => { it('should return 200 if the server has started', async () => { - const service = new DefaultHealthService({ + const service = new DefaultRootHealthService({ lifecycle: mockServices.rootLifecycle.mock(), }); diff --git a/packages/backend-defaults/src/entrypoints/health/healthServiceFactory.ts b/packages/backend-defaults/src/entrypoints/rootHealth/rootHealthServiceFactory.ts similarity index 88% rename from packages/backend-defaults/src/entrypoints/health/healthServiceFactory.ts rename to packages/backend-defaults/src/entrypoints/rootHealth/rootHealthServiceFactory.ts index 652ad8758f..3a00db8285 100644 --- a/packages/backend-defaults/src/entrypoints/health/healthServiceFactory.ts +++ b/packages/backend-defaults/src/entrypoints/rootHealth/rootHealthServiceFactory.ts @@ -15,14 +15,14 @@ */ import { - HealthService, + RootHealthService, RootLifecycleService, coreServices, createServiceFactory, } from '@backstage/backend-plugin-api'; /** @internal */ -export class DefaultHealthService implements HealthService { +export class DefaultRootHealthService implements RootHealthService { #isRunning = false; constructor(readonly options: { lifecycle: RootLifecycleService }) { @@ -53,12 +53,12 @@ export class DefaultHealthService implements HealthService { /** * @public */ -export const healthServiceFactory = createServiceFactory({ +export const rootHealthServiceFactory = createServiceFactory({ service: coreServices.health, deps: { lifecycle: coreServices.rootLifecycle, }, async factory({ lifecycle }) { - return new DefaultHealthService({ lifecycle }); + return new DefaultRootHealthService({ lifecycle }); }, }); diff --git a/packages/backend-defaults/src/entrypoints/rootHttpRouter/createHealthRouter.ts b/packages/backend-defaults/src/entrypoints/rootHttpRouter/createHealthRouter.ts index 012a268e02..13691ede28 100644 --- a/packages/backend-defaults/src/entrypoints/rootHttpRouter/createHealthRouter.ts +++ b/packages/backend-defaults/src/entrypoints/rootHttpRouter/createHealthRouter.ts @@ -1,4 +1,4 @@ -import { HealthService } from '@backstage/backend-plugin-api'; +import { RootHealthService } from '@backstage/backend-plugin-api'; /* * Copyright 2024 The Backstage Authors @@ -19,7 +19,7 @@ import { HealthService } from '@backstage/backend-plugin-api'; import Router from 'express-promise-router'; import { Request, Response } from 'express'; -export function createHealthRouter(options: { health: HealthService }) { +export function createHealthRouter(options: { health: RootHealthService }) { const router = Router(); router.get( diff --git a/packages/backend-plugin-api/src/services/definitions/HealthService.ts b/packages/backend-plugin-api/src/services/definitions/RootHealthService.ts similarity index 83% rename from packages/backend-plugin-api/src/services/definitions/HealthService.ts rename to packages/backend-plugin-api/src/services/definitions/RootHealthService.ts index b2dc4f415e..ac482b5dbb 100644 --- a/packages/backend-plugin-api/src/services/definitions/HealthService.ts +++ b/packages/backend-plugin-api/src/services/definitions/RootHealthService.ts @@ -17,7 +17,13 @@ /** * @public */ -export interface HealthService { +export interface RootHealthService { + /** + * Get the liveness status of the backend. + */ getLiveness(): Promise<{ status: number; payload?: any }>; + /** + * Get the readiness status of the backend. + */ getReadiness(): Promise<{ status: number; payload?: any }>; } diff --git a/packages/backend-plugin-api/src/services/definitions/index.ts b/packages/backend-plugin-api/src/services/definitions/index.ts index af0d991f58..5e30d444fd 100644 --- a/packages/backend-plugin-api/src/services/definitions/index.ts +++ b/packages/backend-plugin-api/src/services/definitions/index.ts @@ -32,7 +32,7 @@ export type { export type { RootConfigService } from './RootConfigService'; export type { DatabaseService } from './DatabaseService'; export type { DiscoveryService } from './DiscoveryService'; -export type { HealthService } from './HealthService'; +export type { RootHealthService } from './RootHealthService'; export type { HttpRouterService, HttpRouterServiceAuthPolicy, diff --git a/packages/backend-test-utils/src/next/services/mockServices.ts b/packages/backend-test-utils/src/next/services/mockServices.ts index a59d053b95..5055a9eae8 100644 --- a/packages/backend-test-utils/src/next/services/mockServices.ts +++ b/packages/backend-test-utils/src/next/services/mockServices.ts @@ -20,11 +20,11 @@ import { HostDiscovery, discoveryServiceFactory, } from '@backstage/backend-defaults/discovery'; -import { healthServiceFactory } from '@backstage/backend-defaults/health'; import { httpRouterServiceFactory } from '@backstage/backend-defaults/httpRouter'; import { lifecycleServiceFactory } from '@backstage/backend-defaults/lifecycle'; import { loggerServiceFactory } from '@backstage/backend-defaults/logger'; import { permissionsServiceFactory } from '@backstage/backend-defaults/permissions'; +import { rootHealthServiceFactory } from '@backstage/backend-defaults/rootHealth'; import { rootHttpRouterServiceFactory } from '@backstage/backend-defaults/rootHttpRouter'; import { rootLifecycleServiceFactory } from '@backstage/backend-defaults/rootLifecycle'; import { schedulerServiceFactory } from '@backstage/backend-defaults/scheduler'; @@ -345,8 +345,8 @@ export namespace mockServices { })); } - export namespace health { - export const factory = healthServiceFactory; + export namespace rootHealth { + export const factory = rootHealthServiceFactory; export const mock = simpleMock(coreServices.health, () => ({ getLiveness: jest.fn(), getReadiness: jest.fn(), From 5c4e876e62afbfa56ff3105a2eca0811a7942e8f Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Thu, 13 Jun 2024 14:25:02 +0200 Subject: [PATCH 19/26] health api reports Signed-off-by: Vincenzo Scamporlino --- ...ort-health.md => api-report-rootHealth.md} | 7 +++-- packages/backend-plugin-api/api-report.md | 28 +++++++++---------- 2 files changed, 18 insertions(+), 17 deletions(-) rename packages/backend-defaults/{api-report-health.md => api-report-rootHealth.md} (65%) diff --git a/packages/backend-defaults/api-report-health.md b/packages/backend-defaults/api-report-rootHealth.md similarity index 65% rename from packages/backend-defaults/api-report-health.md rename to packages/backend-defaults/api-report-rootHealth.md index 795bdaac78..ffa067605a 100644 --- a/packages/backend-defaults/api-report-health.md +++ b/packages/backend-defaults/api-report-rootHealth.md @@ -3,11 +3,14 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts -import { HealthService } from '@backstage/backend-plugin-api'; +import { RootHealthService } from '@backstage/backend-plugin-api'; import { ServiceFactory } from '@backstage/backend-plugin-api'; // @public (undocumented) -export const healthServiceFactory: () => ServiceFactory; +export const rootHealthServiceFactory: () => ServiceFactory< + RootHealthService, + 'root' +>; // (No @packageDocumentation comment for this package) ``` diff --git a/packages/backend-plugin-api/api-report.md b/packages/backend-plugin-api/api-report.md index ee5aecd63b..f527e366c0 100644 --- a/packages/backend-plugin-api/api-report.md +++ b/packages/backend-plugin-api/api-report.md @@ -194,7 +194,7 @@ export namespace coreServices { const rootConfig: ServiceRef; const database: ServiceRef; const discovery: ServiceRef; - const health: ServiceRef; + const health: ServiceRef; const httpAuth: ServiceRef; const httpRouter: ServiceRef; const lifecycle: ServiceRef; @@ -334,20 +334,6 @@ export type ExtensionPoint = { // @public @deprecated (undocumented) export type ExtensionPointConfig = CreateExtensionPointOptions; -// @public (undocumented) -export interface HealthService { - // (undocumented) - getLiveness(): Promise<{ - status: number; - payload?: any; - }>; - // (undocumented) - getReadiness(): Promise<{ - status: number; - payload?: any; - }>; -} - // @public export interface HttpAuthService { credentials( @@ -515,6 +501,18 @@ export function resolveSafeChildPath(base: string, path: string): string; // @public export interface RootConfigService extends Config {} +// @public (undocumented) +export interface RootHealthService { + getLiveness(): Promise<{ + status: number; + payload?: any; + }>; + getReadiness(): Promise<{ + status: number; + payload?: any; + }>; +} + // @public export interface RootHttpRouterService { use(path: string, handler: Handler): void; From 73a45650e2872fdad10ea9edc9f37baa1e847957 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Thu, 20 Jun 2024 12:11:08 +0200 Subject: [PATCH 20/26] api reports Signed-off-by: Vincenzo Scamporlino --- packages/backend-app-api/api-report.md | 4 ---- .../api-report-rootHttpRouter.md | 2 ++ .../rootHealth/rootHealthServiceFactory.ts | 2 +- .../rootHttpRouterServiceFactory.ts | 2 +- packages/backend-plugin-api/api-report.md | 2 +- .../src/services/definitions/coreServices.ts | 4 ++-- packages/backend-test-utils/api-report.md | 20 +++++++++---------- .../src/next/services/mockServices.ts | 2 +- 8 files changed, 18 insertions(+), 20 deletions(-) diff --git a/packages/backend-app-api/api-report.md b/packages/backend-app-api/api-report.md index a18f027273..7518f8e2cc 100644 --- a/packages/backend-app-api/api-report.md +++ b/packages/backend-app-api/api-report.md @@ -18,7 +18,6 @@ import { ErrorRequestHandler } from 'express'; import { Express as Express_2 } from 'express'; import { Format } from 'logform'; import { Handler } from 'express'; -import { HealthService } from '@backstage/backend-plugin-api'; import { HelmetOptions } from 'helmet'; import * as http from 'http'; import { HttpAuthService } from '@backstage/backend-plugin-api'; @@ -127,9 +126,6 @@ export const discoveryServiceFactory: () => ServiceFactory< // @public @deprecated (undocumented) export type ExtendedHttpServer = ExtendedHttpServer_2; -// @public (undocumented) -export const healthServiceFactory: () => ServiceFactory; - // @public @deprecated export class HostDiscovery implements DiscoveryService { static fromConfig( diff --git a/packages/backend-defaults/api-report-rootHttpRouter.md b/packages/backend-defaults/api-report-rootHttpRouter.md index b753406202..d9727fd36d 100644 --- a/packages/backend-defaults/api-report-rootHttpRouter.md +++ b/packages/backend-defaults/api-report-rootHttpRouter.md @@ -121,6 +121,8 @@ export interface RootHttpRouterConfigureContext { // (undocumented) config: RootConfigService; // (undocumented) + healthRouter: RequestHandler; + // (undocumented) lifecycle: LifecycleService; // (undocumented) logger: LoggerService; diff --git a/packages/backend-defaults/src/entrypoints/rootHealth/rootHealthServiceFactory.ts b/packages/backend-defaults/src/entrypoints/rootHealth/rootHealthServiceFactory.ts index 3a00db8285..c8b4ad5394 100644 --- a/packages/backend-defaults/src/entrypoints/rootHealth/rootHealthServiceFactory.ts +++ b/packages/backend-defaults/src/entrypoints/rootHealth/rootHealthServiceFactory.ts @@ -54,7 +54,7 @@ export class DefaultRootHealthService implements RootHealthService { * @public */ export const rootHealthServiceFactory = createServiceFactory({ - service: coreServices.health, + service: coreServices.rootHealth, deps: { lifecycle: coreServices.rootLifecycle, }, diff --git a/packages/backend-defaults/src/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.ts b/packages/backend-defaults/src/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.ts index 5f22cf5ced..22f5c2f310 100644 --- a/packages/backend-defaults/src/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.ts +++ b/packages/backend-defaults/src/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.ts @@ -77,7 +77,7 @@ export const rootHttpRouterServiceFactory = createServiceFactory( config: coreServices.rootConfig, rootLogger: coreServices.rootLogger, lifecycle: coreServices.rootLifecycle, - health: coreServices.health, + health: coreServices.rootHealth, }, async factory({ config, rootLogger, lifecycle, health }) { const { indexPath, configure = defaultConfigure } = options ?? {}; diff --git a/packages/backend-plugin-api/api-report.md b/packages/backend-plugin-api/api-report.md index f527e366c0..ef5aa22cf4 100644 --- a/packages/backend-plugin-api/api-report.md +++ b/packages/backend-plugin-api/api-report.md @@ -194,7 +194,7 @@ export namespace coreServices { const rootConfig: ServiceRef; const database: ServiceRef; const discovery: ServiceRef; - const health: ServiceRef; + const rootHealth: ServiceRef; const httpAuth: ServiceRef; const httpRouter: ServiceRef; const lifecycle: ServiceRef; diff --git a/packages/backend-plugin-api/src/services/definitions/coreServices.ts b/packages/backend-plugin-api/src/services/definitions/coreServices.ts index 36ec0151c5..33d1da2903 100644 --- a/packages/backend-plugin-api/src/services/definitions/coreServices.ts +++ b/packages/backend-plugin-api/src/services/definitions/coreServices.ts @@ -105,9 +105,9 @@ export namespace coreServices { /** * The service reference for the plugin scoped {@link RootHealthService}. */ - export const health = createServiceRef< + export const rootHealth = createServiceRef< import('./RootHealthService').RootHealthService - >({ id: 'core.health', scope: 'root' }); + >({ id: 'core.rootHealth', scope: 'root' }); /** * Authentication of HTTP requests. diff --git a/packages/backend-test-utils/api-report.md b/packages/backend-test-utils/api-report.md index 07b393b653..a2fb4b7674 100644 --- a/packages/backend-test-utils/api-report.md +++ b/packages/backend-test-utils/api-report.md @@ -21,7 +21,6 @@ import { DiscoveryService } from '@backstage/backend-plugin-api'; import { EventsService } from '@backstage/plugin-events-node'; import { ExtendedHttpServer } from '@backstage/backend-app-api'; import { ExtensionPoint } from '@backstage/backend-plugin-api'; -import { HealthService } from '@backstage/backend-plugin-api'; import { HttpAuthService } from '@backstage/backend-plugin-api'; import { HttpRouterFactoryOptions } from '@backstage/backend-defaults/httpRouter'; import { HttpRouterService } from '@backstage/backend-plugin-api'; @@ -33,6 +32,7 @@ import { LifecycleService } from '@backstage/backend-plugin-api'; import { LoggerService } from '@backstage/backend-plugin-api'; import { PermissionsService } from '@backstage/backend-plugin-api'; import { RootConfigService } from '@backstage/backend-plugin-api'; +import { RootHealthService } from '@backstage/backend-plugin-api'; import { RootHttpRouterFactoryOptions } from '@backstage/backend-defaults/rootHttpRouter'; import { RootHttpRouterService } from '@backstage/backend-plugin-api'; import { RootLifecycleService } from '@backstage/backend-plugin-api'; @@ -200,15 +200,6 @@ export namespace mockServices { partialImpl?: Partial | undefined, ) => ServiceMock; } - // (undocumented) - export namespace health { - const // (undocumented) - factory: () => ServiceFactory; - const // (undocumented) - mock: ( - partialImpl?: Partial | undefined, - ) => ServiceMock; - } export function httpAuth(options?: { pluginId?: string; defaultCredentials?: BackstageCredentials; @@ -290,6 +281,15 @@ export namespace mockServices { ) => ServiceFactory; } // (undocumented) + export namespace rootHealth { + const // (undocumented) + factory: () => ServiceFactory; + const // (undocumented) + mock: ( + partialImpl?: Partial | undefined, + ) => ServiceMock; + } + // (undocumented) export namespace rootHttpRouter { const // (undocumented) factory: ( diff --git a/packages/backend-test-utils/src/next/services/mockServices.ts b/packages/backend-test-utils/src/next/services/mockServices.ts index 5055a9eae8..d56179d958 100644 --- a/packages/backend-test-utils/src/next/services/mockServices.ts +++ b/packages/backend-test-utils/src/next/services/mockServices.ts @@ -347,7 +347,7 @@ export namespace mockServices { export namespace rootHealth { export const factory = rootHealthServiceFactory; - export const mock = simpleMock(coreServices.health, () => ({ + export const mock = simpleMock(coreServices.rootHealth, () => ({ getLiveness: jest.fn(), getReadiness: jest.fn(), })); From e36e507d592c3a6011b6834cd8a0b751bc38c339 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Thu, 20 Jun 2024 12:20:18 +0200 Subject: [PATCH 21/26] docs: update root health docs Signed-off-by: Vincenzo Scamporlino --- .../core-services/root-health.md | 40 ++++++++++--------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/docs/backend-system/core-services/root-health.md b/docs/backend-system/core-services/root-health.md index 9a69891624..2a6625fd70 100644 --- a/docs/backend-system/core-services/root-health.md +++ b/docs/backend-system/core-services/root-health.md @@ -1,38 +1,40 @@ --- -id: health -title: Heath Service +id: root-health +title: Root Health Service sidebar_label: Health description: Documentation for the Health service --- -The Health service provides some health check endpoints for the plugins. By default, it attaches `/.backstage/health/v1/readiness` and `/.backstage/health/v1/liveness` endpoints to the backend server, which return a JSON object with the status of the backend services. +The Root Health service provides some health check endpoints for the backend. By default, the `rootHttpRouter` exposes a `/.backstage/health/v1/readiness` and `/.backstage/health/v1/liveness` endpoints, which return a JSON object with the status of the backend services according the implementation of the Root Health Service. ## Configuring the service -The following example is how you can override the health service to add custom endpoints. +The following example is how you can override the health service implementation. ```ts -import { coreServices } from '@backstage/backend-plugin-api'; +import { RootHealthService, coreServices } from '@backstage/backend-plugin-api'; import { WinstonLogger } from '@backstage/backend-app-api'; const backend = createBackend(); +class MyRootHealthService implements RootHealthService { + async getLiveness(): Promise<{ status: number; payload?: any }> { + // provide your own implementation + return { status: 200, payload: { status: 'ok' } }; + } + + async getReadiness(): Promise<{ status: number; payload?: any }> { + // provide your own implementation + return { status: 200, payload: { status: 'ok' } }; + } +} + backend.add( createServiceFactory({ - service: coreServices.health, - deps: { - rootHttpRouter: coreServices.rootHttpRouter, - }, - async factory({ rootHttpRouter }) { - rootHttpRouter.get('.backstage/health/v1/readiness', async (req, res) => { - res.json({ status: 'ok' }); - }); - - rootHttpRouter.get('.backstage/health/v1/liveness', async (req, res) => { - res.json({ status: 'ok' }); - }); - - return {}; + service: coreServices.rootHealth, + deps: {}, + async factory({}) { + return new MyRootHealthService(); }, }), ); From 4e8455f0bd18bf4e779df3b2484f9ac1dfd2430f Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Thu, 20 Jun 2024 12:43:34 +0200 Subject: [PATCH 22/26] Apply suggestions from code review Signed-off-by: Vincenzo Scamporlino --- .changeset/bright-panthers-leave.md | 2 +- .changeset/serious-kings-trade.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.changeset/bright-panthers-leave.md b/.changeset/bright-panthers-leave.md index acd9764fe6..14798b6b39 100644 --- a/.changeset/bright-panthers-leave.md +++ b/.changeset/bright-panthers-leave.md @@ -4,4 +4,4 @@ '@backstage/backend-app-api': patch --- -Added a new health service which adds new endpoints for health checks. +Added a new Root Health Service which adds new endpoints for health checks. diff --git a/.changeset/serious-kings-trade.md b/.changeset/serious-kings-trade.md index c07e92b88a..826392bf98 100644 --- a/.changeset/serious-kings-trade.md +++ b/.changeset/serious-kings-trade.md @@ -2,4 +2,4 @@ '@backstage/backend-test-utils': patch --- -Added mock for health service in `mockServices`. +Added mock for the Root Health Service in `mockServices`. From 73b4e727e9a3c31460f1b8ba4533562404a9b2ad Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Thu, 20 Jun 2024 15:22:35 +0200 Subject: [PATCH 23/26] Update .changeset/bright-panthers-leave.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Fredrik Adelöw Signed-off-by: Vincenzo Scamporlino --- .changeset/bright-panthers-leave.md | 1 - 1 file changed, 1 deletion(-) diff --git a/.changeset/bright-panthers-leave.md b/.changeset/bright-panthers-leave.md index 14798b6b39..35d9c0f869 100644 --- a/.changeset/bright-panthers-leave.md +++ b/.changeset/bright-panthers-leave.md @@ -1,7 +1,6 @@ --- '@backstage/backend-plugin-api': patch '@backstage/backend-defaults': patch -'@backstage/backend-app-api': patch --- Added a new Root Health Service which adds new endpoints for health checks. From cd22b4066660158b247ba2c9d728f6a777e44351 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Thu, 20 Jun 2024 15:31:34 +0200 Subject: [PATCH 24/26] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Fredrik Adelöw Signed-off-by: Vincenzo Scamporlino --- docs/backend-system/core-services/root-health.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/backend-system/core-services/root-health.md b/docs/backend-system/core-services/root-health.md index 2a6625fd70..cdf18aa1f9 100644 --- a/docs/backend-system/core-services/root-health.md +++ b/docs/backend-system/core-services/root-health.md @@ -9,11 +9,10 @@ The Root Health service provides some health check endpoints for the backend. By ## Configuring the service -The following example is how you can override the health service implementation. +The following example shows how you can override the root health service implementation. ```ts import { RootHealthService, coreServices } from '@backstage/backend-plugin-api'; -import { WinstonLogger } from '@backstage/backend-app-api'; const backend = createBackend(); From 7df5c8875c12058e6b3e61827f074c324e3d82c0 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Thu, 20 Jun 2024 15:41:19 +0200 Subject: [PATCH 25/26] backend-defaults: test tweaks Signed-off-by: Vincenzo Scamporlino --- .../rootHealthServiceFactory.test.ts | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/packages/backend-defaults/src/entrypoints/rootHealth/rootHealthServiceFactory.test.ts b/packages/backend-defaults/src/entrypoints/rootHealth/rootHealthServiceFactory.test.ts index fd786e2b28..0eee5c18c6 100644 --- a/packages/backend-defaults/src/entrypoints/rootHealth/rootHealthServiceFactory.test.ts +++ b/packages/backend-defaults/src/entrypoints/rootHealth/rootHealthServiceFactory.test.ts @@ -1,6 +1,3 @@ -import { mockServices } from '@backstage/backend-test-utils'; -import { DefaultRootHealthService } from './rootHealthServiceFactory'; - /* * Copyright 2024 The Backstage Authors * @@ -16,6 +13,10 @@ import { DefaultRootHealthService } from './rootHealthServiceFactory'; * See the License for the specific language governing permissions and * limitations under the License. */ + +import { mockServices } from '@backstage/backend-test-utils'; +import { DefaultRootHealthService } from './rootHealthServiceFactory'; + describe('DefaultRootHealthService', () => { describe('readiness', () => { it(`should return a 500 response if the server hasn't started yet`, async () => { @@ -32,11 +33,11 @@ describe('DefaultRootHealthService', () => { }); it('should return 200 if the server has started', async () => { - const lifecycle = mockServices.rootLifecycle.mock(); let mockServerStartedFn = () => {}; - lifecycle.addStartupHook.mockImplementation( - fn => (mockServerStartedFn = fn), - ); + + const lifecycle = mockServices.rootLifecycle.mock({ + addStartupHook: jest.fn(fn => (mockServerStartedFn = fn)), + }); const service = new DefaultRootHealthService({ lifecycle, @@ -51,18 +52,16 @@ describe('DefaultRootHealthService', () => { }); it(`should return a 500 response if the server has stopped`, async () => { - const lifecycle = mockServices.rootLifecycle.mock(); let mockServerStartedFn = () => {}; let mockServerStoppedFn = () => {}; - lifecycle.addStartupHook.mockImplementation( - fn => (mockServerStartedFn = fn), - ); - lifecycle.addShutdownHook.mockImplementation( - fn => (mockServerStoppedFn = fn), - ); + + const lifecycle = mockServices.rootLifecycle.mock({ + addStartupHook: jest.fn(fn => (mockServerStartedFn = fn)), + addShutdownHook: jest.fn(fn => (mockServerStoppedFn = fn)), + }); const service = new DefaultRootHealthService({ - lifecycle: mockServices.rootLifecycle.mock(), + lifecycle, }); mockServerStartedFn(); From 878f2efc514810e03567d167b61b92f66cd74790 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Thu, 20 Jun 2024 15:45:02 +0200 Subject: [PATCH 26/26] backend-plugin-api: fix typings in health service Signed-off-by: Vincenzo Scamporlino --- docs/backend-system/core-services/root-health.md | 4 ++-- packages/backend-plugin-api/api-report.md | 4 ++-- .../src/services/definitions/RootHealthService.ts | 6 ++++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/docs/backend-system/core-services/root-health.md b/docs/backend-system/core-services/root-health.md index cdf18aa1f9..fc73ba9546 100644 --- a/docs/backend-system/core-services/root-health.md +++ b/docs/backend-system/core-services/root-health.md @@ -17,12 +17,12 @@ import { RootHealthService, coreServices } from '@backstage/backend-plugin-api'; const backend = createBackend(); class MyRootHealthService implements RootHealthService { - async getLiveness(): Promise<{ status: number; payload?: any }> { + async getLiveness() { // provide your own implementation return { status: 200, payload: { status: 'ok' } }; } - async getReadiness(): Promise<{ status: number; payload?: any }> { + async getReadiness() { // provide your own implementation return { status: 200, payload: { status: 'ok' } }; } diff --git a/packages/backend-plugin-api/api-report.md b/packages/backend-plugin-api/api-report.md index ef5aa22cf4..e9762f652e 100644 --- a/packages/backend-plugin-api/api-report.md +++ b/packages/backend-plugin-api/api-report.md @@ -505,11 +505,11 @@ export interface RootConfigService extends Config {} export interface RootHealthService { getLiveness(): Promise<{ status: number; - payload?: any; + payload?: JsonValue; }>; getReadiness(): Promise<{ status: number; - payload?: any; + payload?: JsonValue; }>; } diff --git a/packages/backend-plugin-api/src/services/definitions/RootHealthService.ts b/packages/backend-plugin-api/src/services/definitions/RootHealthService.ts index ac482b5dbb..e6c56e8654 100644 --- a/packages/backend-plugin-api/src/services/definitions/RootHealthService.ts +++ b/packages/backend-plugin-api/src/services/definitions/RootHealthService.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { JsonValue } from '@backstage/types'; + /** * @public */ @@ -21,9 +23,9 @@ export interface RootHealthService { /** * Get the liveness status of the backend. */ - getLiveness(): Promise<{ status: number; payload?: any }>; + getLiveness(): Promise<{ status: number; payload?: JsonValue }>; /** * Get the readiness status of the backend. */ - getReadiness(): Promise<{ status: number; payload?: any }>; + getReadiness(): Promise<{ status: number; payload?: JsonValue }>; }