backend-app-api: move healthchecks to healthService
Signed-off-by: Vincenzo Scamporlino <vincenzos@spotify.com>
This commit is contained in:
+81
@@ -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' });
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 {};
|
||||
},
|
||||
});
|
||||
@@ -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';
|
||||
@@ -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 {}
|
||||
@@ -26,11 +26,6 @@ export interface HttpRouterServiceAuthPolicy {
|
||||
allow: 'unauthenticated' | 'user-cookie';
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export interface HttpRouterHealthCheckConfig {
|
||||
handler: () => Promise<any>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows plugins to register HTTP routes.
|
||||
*
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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(),
|
||||
}));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user