diff --git a/packages/backend-app-api/api-report.md b/packages/backend-app-api/api-report.md index cde0ef64d2..5f452f9e03 100644 --- a/packages/backend-app-api/api-report.md +++ b/packages/backend-app-api/api-report.md @@ -18,6 +18,7 @@ import { Handler } from 'express'; import { HelmetOptions } from 'helmet'; import * as http from 'http'; import { HttpRouterService } from '@backstage/backend-plugin-api'; +import { HumanDuration } from '@backstage/types'; import { IdentityService } from '@backstage/backend-plugin-api'; import { JsonObject } from '@backstage/types'; import { LifecycleService } from '@backstage/backend-plugin-api'; @@ -179,8 +180,7 @@ export const identityServiceFactory: ( export interface LifecycleMiddlewareOptions { // (undocumented) lifecycle: LifecycleService; - // (undocumented) - timeoutMs?: number; + startupRequestPauseTimeout?: HumanDuration; } // @public diff --git a/packages/backend-app-api/src/services/implementations/httpRouter/createLifecycleMiddleware.test.ts b/packages/backend-app-api/src/services/implementations/httpRouter/createLifecycleMiddleware.test.ts index e1091d247f..31eecf14bb 100644 --- a/packages/backend-app-api/src/services/implementations/httpRouter/createLifecycleMiddleware.test.ts +++ b/packages/backend-app-api/src/services/implementations/httpRouter/createLifecycleMiddleware.test.ts @@ -63,7 +63,10 @@ describe('createLifecycleMiddleware', () => { it('should throw ServiceUnavailableError after timeout', async () => { const lifecycle = new BackendLifecycleImpl(mockServices.rootLogger()); - const middleware = createLifecycleMiddleware({ lifecycle, timeoutMs: 1 }); + const middleware = createLifecycleMiddleware({ + lifecycle, + startupRequestPauseTimeout: { milliseconds: 1 }, + }); const next = jest.fn(); middleware({} as any, {} as any, next); diff --git a/packages/backend-app-api/src/services/implementations/httpRouter/createLifecycleMiddleware.ts b/packages/backend-app-api/src/services/implementations/httpRouter/createLifecycleMiddleware.ts index b2a41bbb2f..e5e829eebe 100644 --- a/packages/backend-app-api/src/services/implementations/httpRouter/createLifecycleMiddleware.ts +++ b/packages/backend-app-api/src/services/implementations/httpRouter/createLifecycleMiddleware.ts @@ -16,9 +16,31 @@ import { LifecycleService } from '@backstage/backend-plugin-api'; import { ServiceUnavailableError } from '@backstage/errors'; +import { HumanDuration } from '@backstage/types'; import { RequestHandler } from 'express'; -export const DEFAULT_TIMEOUT_MS = 5000; +export const DEFAULT_TIMEOUT = { seconds: 5 }; + +function durationToMs(duration: HumanDuration): number { + const { + years = 0, + months = 0, + weeks = 0, + days = 0, + hours = 0, + minutes = 0, + seconds = 0, + milliseconds = 0, + } = duration; + + const totalDays = years * 365 + months * 30 + weeks * 7 + days; + const totalHours = totalDays * 24 + hours; + const totalMinutes = totalHours * 60 + minutes; + const totalSeconds = totalMinutes * 60 + seconds; + const totalMilliseconds = totalSeconds * 1000 + milliseconds; + + return totalMilliseconds; +} /** * Options for {@link createLifecycleMiddleware}. @@ -26,7 +48,10 @@ export const DEFAULT_TIMEOUT_MS = 5000; */ export interface LifecycleMiddlewareOptions { lifecycle: LifecycleService; - timeoutMs?: number; + /** + * The maximum time that paused requests will wait for the service to start, before returning an error. + */ + startupRequestPauseTimeout?: HumanDuration; } /** @@ -46,7 +71,7 @@ export interface LifecycleMiddlewareOptions { export function createLifecycleMiddleware( options: LifecycleMiddlewareOptions, ): RequestHandler { - const { lifecycle, timeoutMs = DEFAULT_TIMEOUT_MS } = options; + const { lifecycle, startupRequestPauseTimeout = DEFAULT_TIMEOUT } = options; let state: 'init' | 'up' | 'down' = 'init'; const waiting = new Set<{ @@ -75,6 +100,8 @@ export function createLifecycleMiddleware( waiting.clear(); }); + const timeoutMs = durationToMs(startupRequestPauseTimeout); + return (_req, _res, next) => { if (state === 'up') { next();