backend-app-api: flip logic of health service
Signed-off-by: Vincenzo Scamporlino <vincenzos@spotify.com>
This commit is contained in:
@@ -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',
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
+8
-1
@@ -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());
|
||||
|
||||
@@ -335,7 +335,18 @@ export type ExtensionPoint<T> = {
|
||||
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 {
|
||||
|
||||
@@ -17,4 +17,7 @@
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface HealthService {}
|
||||
export interface HealthService {
|
||||
getLiveness(): Promise<{ status: number; payload?: any }>;
|
||||
getReadiness(): Promise<{ status: number; payload?: any }>;
|
||||
}
|
||||
|
||||
@@ -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, () => ({
|
||||
|
||||
Reference in New Issue
Block a user