@autofleet/nitur 3.0.0-beta.0 → 3.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,2 +1,2 @@
1
- const e=require(`./types.cjs`),t=require(`./health-check-handlers.cjs`),n=require(`./shutdown-handlers.cjs`),r={[e.CLIENT_TYPES.RABBIT]:{healthCheck:t.DEFAULT_CLIENT_HEALTHCHECK_FUNC_MAP[e.CLIENT_TYPES.RABBIT],shutdownHandlers:n.DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP[e.CLIENT_TYPES.RABBIT],options:{shutdownStages:[e.SHUTDOWN_STAGES.STOP_ACCEPTING_WORK],includeInLivenessCheck:!0,includeInReadinessCheck:!0,name:`RabbitMQ Client`}},[e.CLIENT_TYPES.SEQUELIZE]:{healthCheck:t.DEFAULT_CLIENT_HEALTHCHECK_FUNC_MAP[e.CLIENT_TYPES.SEQUELIZE],shutdownHandlers:n.DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP[e.CLIENT_TYPES.SEQUELIZE],options:{shutdownStages:[e.SHUTDOWN_STAGES.CLOSE],includeInLivenessCheck:!0,includeInReadinessCheck:!0,name:`Sequelize Client`}},[e.CLIENT_TYPES.REDIS]:{healthCheck:t.DEFAULT_CLIENT_HEALTHCHECK_FUNC_MAP[e.CLIENT_TYPES.REDIS],shutdownHandlers:n.DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP[e.CLIENT_TYPES.REDIS],options:{shutdownStages:[e.SHUTDOWN_STAGES.CLOSE],includeInLivenessCheck:!0,includeInReadinessCheck:!0,name:`Redis Client`}},[e.CLIENT_TYPES.ELASTIC_SEARCH]:{healthCheck:t.DEFAULT_CLIENT_HEALTHCHECK_FUNC_MAP[e.CLIENT_TYPES.ELASTIC_SEARCH],shutdownHandlers:n.DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP[e.CLIENT_TYPES.ELASTIC_SEARCH],options:{shutdownStages:[e.SHUTDOWN_STAGES.CLOSE],includeInLivenessCheck:!0,includeInReadinessCheck:!0,name:`Elasticsearch Client`}},[e.CLIENT_TYPES.EVENTS]:{shutdownHandlers:n.DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP[e.CLIENT_TYPES.EVENTS],options:{shutdownStages:[e.SHUTDOWN_STAGES.CLOSE],includeInLivenessCheck:!1,includeInReadinessCheck:!1,name:`Events Client`}},[e.CLIENT_TYPES.SERVER]:{shutdownHandlers:n.DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP[e.CLIENT_TYPES.SERVER],options:{shutdownStages:[e.SHUTDOWN_STAGES.STOP_ACCEPTING_WORK],includeInLivenessCheck:!1,includeInReadinessCheck:!1,name:`HTTP Server`}},[e.CLIENT_TYPES.CUSTOM]:{options:{includeInLivenessCheck:!0,includeInReadinessCheck:!0,name:`Custom Client`}}};exports.CLIENT_DEFAULTS_MAP=r;
1
+ const e=require(`./types.cjs`),t=require(`./health-check-handlers.cjs`),n=require(`./shutdown-handlers.cjs`),r={[e.CLIENT_TYPES.RABBIT]:{healthCheck:t.DEFAULT_CLIENT_HEALTHCHECK_FUNC_MAP[e.CLIENT_TYPES.RABBIT],shutdownHandlers:n.DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP[e.CLIENT_TYPES.RABBIT],options:{enabledShutdownStages:[e.SHUTDOWN_STAGES.STOP_ACCEPTING_WORK],includeInLivenessCheck:!0,includeInReadinessCheck:!0,name:`RabbitMQ Client`}},[e.CLIENT_TYPES.SEQUELIZE]:{healthCheck:t.DEFAULT_CLIENT_HEALTHCHECK_FUNC_MAP[e.CLIENT_TYPES.SEQUELIZE],shutdownHandlers:n.DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP[e.CLIENT_TYPES.SEQUELIZE],options:{enabledShutdownStages:[e.SHUTDOWN_STAGES.CLOSE],includeInLivenessCheck:!0,includeInReadinessCheck:!0,name:`Sequelize Client`}},[e.CLIENT_TYPES.REDIS]:{healthCheck:t.DEFAULT_CLIENT_HEALTHCHECK_FUNC_MAP[e.CLIENT_TYPES.REDIS],shutdownHandlers:n.DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP[e.CLIENT_TYPES.REDIS],options:{enabledShutdownStages:[e.SHUTDOWN_STAGES.CLOSE],includeInLivenessCheck:!0,includeInReadinessCheck:!0,name:`Redis Client`}},[e.CLIENT_TYPES.ELASTIC_SEARCH]:{healthCheck:t.DEFAULT_CLIENT_HEALTHCHECK_FUNC_MAP[e.CLIENT_TYPES.ELASTIC_SEARCH],shutdownHandlers:n.DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP[e.CLIENT_TYPES.ELASTIC_SEARCH],options:{enabledShutdownStages:[e.SHUTDOWN_STAGES.CLOSE],includeInLivenessCheck:!0,includeInReadinessCheck:!0,name:`Elasticsearch Client`}},[e.CLIENT_TYPES.EVENTS]:{shutdownHandlers:n.DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP[e.CLIENT_TYPES.EVENTS],options:{enabledShutdownStages:[e.SHUTDOWN_STAGES.CLOSE],includeInLivenessCheck:!1,includeInReadinessCheck:!1,name:`Events Client`}},[e.CLIENT_TYPES.SERVER]:{shutdownHandlers:n.DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP[e.CLIENT_TYPES.SERVER],options:{enabledShutdownStages:[e.SHUTDOWN_STAGES.STOP_ACCEPTING_WORK],includeInLivenessCheck:!1,includeInReadinessCheck:!1,name:`HTTP Server`}},[e.CLIENT_TYPES.CUSTOM]:{options:{includeInLivenessCheck:!0,includeInReadinessCheck:!0,name:`Custom Client`}}};exports.CLIENT_DEFAULTS_MAP=r;
2
2
  //# sourceMappingURL=client-defaults.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"client-defaults.cjs","names":["CLIENT_DEFAULTS_MAP: Partial<Record<ClientType, Omit<ClientConfig, 'connection'>>>","CLIENT_TYPES","DEFAULT_CLIENT_HEALTHCHECK_FUNC_MAP","DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP","SHUTDOWN_STAGES"],"sources":["../../src/health-manager/client-defaults.ts"],"sourcesContent":["import type { ClientConfig, ClientType } from './types';\nimport { CLIENT_TYPES, SHUTDOWN_STAGES } from './types';\nimport { DEFAULT_CLIENT_HEALTHCHECK_FUNC_MAP } from './health-check-handlers';\nimport { DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP } from './shutdown-handlers';\n\nexport const CLIENT_DEFAULTS_MAP: Partial<Record<ClientType, Omit<ClientConfig, 'connection'>>> = {\n [CLIENT_TYPES.RABBIT]: {\n healthCheck: DEFAULT_CLIENT_HEALTHCHECK_FUNC_MAP[CLIENT_TYPES.RABBIT],\n shutdownHandlers: DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP[CLIENT_TYPES.RABBIT],\n options: {\n shutdownStages: [SHUTDOWN_STAGES.STOP_ACCEPTING_WORK],\n includeInLivenessCheck: true,\n includeInReadinessCheck: true,\n name: 'RabbitMQ Client',\n },\n },\n [CLIENT_TYPES.SEQUELIZE]: {\n healthCheck: DEFAULT_CLIENT_HEALTHCHECK_FUNC_MAP[CLIENT_TYPES.SEQUELIZE],\n shutdownHandlers: DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP[CLIENT_TYPES.SEQUELIZE],\n options: {\n shutdownStages: [SHUTDOWN_STAGES.CLOSE],\n includeInLivenessCheck: true,\n includeInReadinessCheck: true,\n name: 'Sequelize Client',\n },\n },\n [CLIENT_TYPES.REDIS]: {\n healthCheck: DEFAULT_CLIENT_HEALTHCHECK_FUNC_MAP[CLIENT_TYPES.REDIS],\n shutdownHandlers: DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP[CLIENT_TYPES.REDIS],\n options: {\n shutdownStages: [SHUTDOWN_STAGES.CLOSE],\n includeInLivenessCheck: true,\n includeInReadinessCheck: true,\n name: 'Redis Client',\n },\n },\n [CLIENT_TYPES.ELASTIC_SEARCH]: {\n healthCheck: DEFAULT_CLIENT_HEALTHCHECK_FUNC_MAP[CLIENT_TYPES.ELASTIC_SEARCH],\n shutdownHandlers: DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP[CLIENT_TYPES.ELASTIC_SEARCH],\n options: {\n shutdownStages: [SHUTDOWN_STAGES.CLOSE],\n includeInLivenessCheck: true,\n includeInReadinessCheck: true,\n name: 'Elasticsearch Client',\n },\n },\n [CLIENT_TYPES.EVENTS]: {\n shutdownHandlers: DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP[CLIENT_TYPES.EVENTS],\n options: {\n shutdownStages: [SHUTDOWN_STAGES.CLOSE],\n includeInLivenessCheck: false,\n includeInReadinessCheck: false,\n name: 'Events Client',\n },\n },\n [CLIENT_TYPES.SERVER]: {\n shutdownHandlers: DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP[CLIENT_TYPES.SERVER],\n options: {\n shutdownStages: [SHUTDOWN_STAGES.STOP_ACCEPTING_WORK],\n includeInLivenessCheck: false,\n includeInReadinessCheck: false,\n name: 'HTTP Server',\n },\n },\n [CLIENT_TYPES.CUSTOM]: {\n options: {\n includeInLivenessCheck: true,\n includeInReadinessCheck: true,\n name: 'Custom Client',\n },\n },\n};\n"],"mappings":"6GAKaA,EAAqF,EAC/FC,EAAAA,aAAa,QAAS,CACrB,YAAaC,EAAAA,oCAAoCD,EAAAA,aAAa,QAC9D,iBAAkBE,EAAAA,qCAAqCF,EAAAA,aAAa,QACpE,QAAS,CACP,eAAgB,CAACG,EAAAA,gBAAgB,oBAAoB,CACrD,uBAAwB,GACxB,wBAAyB,GACzB,KAAM,kBACP,CACF,EACAH,EAAAA,aAAa,WAAY,CACxB,YAAaC,EAAAA,oCAAoCD,EAAAA,aAAa,WAC9D,iBAAkBE,EAAAA,qCAAqCF,EAAAA,aAAa,WACpE,QAAS,CACP,eAAgB,CAACG,EAAAA,gBAAgB,MAAM,CACvC,uBAAwB,GACxB,wBAAyB,GACzB,KAAM,mBACP,CACF,EACAH,EAAAA,aAAa,OAAQ,CACpB,YAAaC,EAAAA,oCAAoCD,EAAAA,aAAa,OAC9D,iBAAkBE,EAAAA,qCAAqCF,EAAAA,aAAa,OACpE,QAAS,CACP,eAAgB,CAACG,EAAAA,gBAAgB,MAAM,CACvC,uBAAwB,GACxB,wBAAyB,GACzB,KAAM,eACP,CACF,EACAH,EAAAA,aAAa,gBAAiB,CAC7B,YAAaC,EAAAA,oCAAoCD,EAAAA,aAAa,gBAC9D,iBAAkBE,EAAAA,qCAAqCF,EAAAA,aAAa,gBACpE,QAAS,CACP,eAAgB,CAACG,EAAAA,gBAAgB,MAAM,CACvC,uBAAwB,GACxB,wBAAyB,GACzB,KAAM,uBACP,CACF,EACAH,EAAAA,aAAa,QAAS,CACrB,iBAAkBE,EAAAA,qCAAqCF,EAAAA,aAAa,QACpE,QAAS,CACP,eAAgB,CAACG,EAAAA,gBAAgB,MAAM,CACvC,uBAAwB,GACxB,wBAAyB,GACzB,KAAM,gBACP,CACF,EACAH,EAAAA,aAAa,QAAS,CACrB,iBAAkBE,EAAAA,qCAAqCF,EAAAA,aAAa,QACpE,QAAS,CACP,eAAgB,CAACG,EAAAA,gBAAgB,oBAAoB,CACrD,uBAAwB,GACxB,wBAAyB,GACzB,KAAM,cACP,CACF,EACAH,EAAAA,aAAa,QAAS,CACrB,QAAS,CACP,uBAAwB,GACxB,wBAAyB,GACzB,KAAM,gBACP,CACF,CACF"}
1
+ {"version":3,"file":"client-defaults.cjs","names":["CLIENT_DEFAULTS_MAP: Partial<Record<ClientType, Omit<ClientConfig, 'connection'>>>","CLIENT_TYPES","DEFAULT_CLIENT_HEALTHCHECK_FUNC_MAP","DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP","SHUTDOWN_STAGES"],"sources":["../../src/health-manager/client-defaults.ts"],"sourcesContent":["import type { ClientConfig, ClientType } from './types';\nimport { CLIENT_TYPES, SHUTDOWN_STAGES } from './types';\nimport { DEFAULT_CLIENT_HEALTHCHECK_FUNC_MAP } from './health-check-handlers';\nimport { DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP } from './shutdown-handlers';\n\nexport const CLIENT_DEFAULTS_MAP: Partial<Record<ClientType, Omit<ClientConfig, 'connection'>>> = {\n [CLIENT_TYPES.RABBIT]: {\n healthCheck: DEFAULT_CLIENT_HEALTHCHECK_FUNC_MAP[CLIENT_TYPES.RABBIT],\n shutdownHandlers: DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP[CLIENT_TYPES.RABBIT],\n options: {\n enabledShutdownStages: [SHUTDOWN_STAGES.STOP_ACCEPTING_WORK],\n includeInLivenessCheck: true,\n includeInReadinessCheck: true,\n name: 'RabbitMQ Client',\n },\n },\n [CLIENT_TYPES.SEQUELIZE]: {\n healthCheck: DEFAULT_CLIENT_HEALTHCHECK_FUNC_MAP[CLIENT_TYPES.SEQUELIZE],\n shutdownHandlers: DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP[CLIENT_TYPES.SEQUELIZE],\n options: {\n enabledShutdownStages: [SHUTDOWN_STAGES.CLOSE],\n includeInLivenessCheck: true,\n includeInReadinessCheck: true,\n name: 'Sequelize Client',\n },\n },\n [CLIENT_TYPES.REDIS]: {\n healthCheck: DEFAULT_CLIENT_HEALTHCHECK_FUNC_MAP[CLIENT_TYPES.REDIS],\n shutdownHandlers: DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP[CLIENT_TYPES.REDIS],\n options: {\n enabledShutdownStages: [SHUTDOWN_STAGES.CLOSE],\n includeInLivenessCheck: true,\n includeInReadinessCheck: true,\n name: 'Redis Client',\n },\n },\n [CLIENT_TYPES.ELASTIC_SEARCH]: {\n healthCheck: DEFAULT_CLIENT_HEALTHCHECK_FUNC_MAP[CLIENT_TYPES.ELASTIC_SEARCH],\n shutdownHandlers: DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP[CLIENT_TYPES.ELASTIC_SEARCH],\n options: {\n enabledShutdownStages: [SHUTDOWN_STAGES.CLOSE],\n includeInLivenessCheck: true,\n includeInReadinessCheck: true,\n name: 'Elasticsearch Client',\n },\n },\n [CLIENT_TYPES.EVENTS]: {\n shutdownHandlers: DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP[CLIENT_TYPES.EVENTS],\n options: {\n enabledShutdownStages: [SHUTDOWN_STAGES.CLOSE],\n includeInLivenessCheck: false,\n includeInReadinessCheck: false,\n name: 'Events Client',\n },\n },\n [CLIENT_TYPES.SERVER]: {\n shutdownHandlers: DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP[CLIENT_TYPES.SERVER],\n options: {\n enabledShutdownStages: [SHUTDOWN_STAGES.STOP_ACCEPTING_WORK],\n includeInLivenessCheck: false,\n includeInReadinessCheck: false,\n name: 'HTTP Server',\n },\n },\n [CLIENT_TYPES.CUSTOM]: {\n options: {\n includeInLivenessCheck: true,\n includeInReadinessCheck: true,\n name: 'Custom Client',\n },\n },\n};\n"],"mappings":"6GAKaA,EAAqF,EAC/FC,EAAAA,aAAa,QAAS,CACrB,YAAaC,EAAAA,oCAAoCD,EAAAA,aAAa,QAC9D,iBAAkBE,EAAAA,qCAAqCF,EAAAA,aAAa,QACpE,QAAS,CACP,sBAAuB,CAACG,EAAAA,gBAAgB,oBAAoB,CAC5D,uBAAwB,GACxB,wBAAyB,GACzB,KAAM,kBACP,CACF,EACAH,EAAAA,aAAa,WAAY,CACxB,YAAaC,EAAAA,oCAAoCD,EAAAA,aAAa,WAC9D,iBAAkBE,EAAAA,qCAAqCF,EAAAA,aAAa,WACpE,QAAS,CACP,sBAAuB,CAACG,EAAAA,gBAAgB,MAAM,CAC9C,uBAAwB,GACxB,wBAAyB,GACzB,KAAM,mBACP,CACF,EACAH,EAAAA,aAAa,OAAQ,CACpB,YAAaC,EAAAA,oCAAoCD,EAAAA,aAAa,OAC9D,iBAAkBE,EAAAA,qCAAqCF,EAAAA,aAAa,OACpE,QAAS,CACP,sBAAuB,CAACG,EAAAA,gBAAgB,MAAM,CAC9C,uBAAwB,GACxB,wBAAyB,GACzB,KAAM,eACP,CACF,EACAH,EAAAA,aAAa,gBAAiB,CAC7B,YAAaC,EAAAA,oCAAoCD,EAAAA,aAAa,gBAC9D,iBAAkBE,EAAAA,qCAAqCF,EAAAA,aAAa,gBACpE,QAAS,CACP,sBAAuB,CAACG,EAAAA,gBAAgB,MAAM,CAC9C,uBAAwB,GACxB,wBAAyB,GACzB,KAAM,uBACP,CACF,EACAH,EAAAA,aAAa,QAAS,CACrB,iBAAkBE,EAAAA,qCAAqCF,EAAAA,aAAa,QACpE,QAAS,CACP,sBAAuB,CAACG,EAAAA,gBAAgB,MAAM,CAC9C,uBAAwB,GACxB,wBAAyB,GACzB,KAAM,gBACP,CACF,EACAH,EAAAA,aAAa,QAAS,CACrB,iBAAkBE,EAAAA,qCAAqCF,EAAAA,aAAa,QACpE,QAAS,CACP,sBAAuB,CAACG,EAAAA,gBAAgB,oBAAoB,CAC5D,uBAAwB,GACxB,wBAAyB,GACzB,KAAM,cACP,CACF,EACAH,EAAAA,aAAa,QAAS,CACrB,QAAS,CACP,uBAAwB,GACxB,wBAAyB,GACzB,KAAM,gBACP,CACF,CACF"}
@@ -1,2 +1,2 @@
1
- import{CLIENT_TYPES as e,SHUTDOWN_STAGES as t}from"./types.js";import{DEFAULT_CLIENT_HEALTHCHECK_FUNC_MAP as n}from"./health-check-handlers.js";import{DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP as r}from"./shutdown-handlers.js";const i={[e.RABBIT]:{healthCheck:n[e.RABBIT],shutdownHandlers:r[e.RABBIT],options:{shutdownStages:[t.STOP_ACCEPTING_WORK],includeInLivenessCheck:!0,includeInReadinessCheck:!0,name:`RabbitMQ Client`}},[e.SEQUELIZE]:{healthCheck:n[e.SEQUELIZE],shutdownHandlers:r[e.SEQUELIZE],options:{shutdownStages:[t.CLOSE],includeInLivenessCheck:!0,includeInReadinessCheck:!0,name:`Sequelize Client`}},[e.REDIS]:{healthCheck:n[e.REDIS],shutdownHandlers:r[e.REDIS],options:{shutdownStages:[t.CLOSE],includeInLivenessCheck:!0,includeInReadinessCheck:!0,name:`Redis Client`}},[e.ELASTIC_SEARCH]:{healthCheck:n[e.ELASTIC_SEARCH],shutdownHandlers:r[e.ELASTIC_SEARCH],options:{shutdownStages:[t.CLOSE],includeInLivenessCheck:!0,includeInReadinessCheck:!0,name:`Elasticsearch Client`}},[e.EVENTS]:{shutdownHandlers:r[e.EVENTS],options:{shutdownStages:[t.CLOSE],includeInLivenessCheck:!1,includeInReadinessCheck:!1,name:`Events Client`}},[e.SERVER]:{shutdownHandlers:r[e.SERVER],options:{shutdownStages:[t.STOP_ACCEPTING_WORK],includeInLivenessCheck:!1,includeInReadinessCheck:!1,name:`HTTP Server`}},[e.CUSTOM]:{options:{includeInLivenessCheck:!0,includeInReadinessCheck:!0,name:`Custom Client`}}};export{i as CLIENT_DEFAULTS_MAP};
1
+ import{CLIENT_TYPES as e,SHUTDOWN_STAGES as t}from"./types.js";import{DEFAULT_CLIENT_HEALTHCHECK_FUNC_MAP as n}from"./health-check-handlers.js";import{DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP as r}from"./shutdown-handlers.js";const i={[e.RABBIT]:{healthCheck:n[e.RABBIT],shutdownHandlers:r[e.RABBIT],options:{enabledShutdownStages:[t.STOP_ACCEPTING_WORK],includeInLivenessCheck:!0,includeInReadinessCheck:!0,name:`RabbitMQ Client`}},[e.SEQUELIZE]:{healthCheck:n[e.SEQUELIZE],shutdownHandlers:r[e.SEQUELIZE],options:{enabledShutdownStages:[t.CLOSE],includeInLivenessCheck:!0,includeInReadinessCheck:!0,name:`Sequelize Client`}},[e.REDIS]:{healthCheck:n[e.REDIS],shutdownHandlers:r[e.REDIS],options:{enabledShutdownStages:[t.CLOSE],includeInLivenessCheck:!0,includeInReadinessCheck:!0,name:`Redis Client`}},[e.ELASTIC_SEARCH]:{healthCheck:n[e.ELASTIC_SEARCH],shutdownHandlers:r[e.ELASTIC_SEARCH],options:{enabledShutdownStages:[t.CLOSE],includeInLivenessCheck:!0,includeInReadinessCheck:!0,name:`Elasticsearch Client`}},[e.EVENTS]:{shutdownHandlers:r[e.EVENTS],options:{enabledShutdownStages:[t.CLOSE],includeInLivenessCheck:!1,includeInReadinessCheck:!1,name:`Events Client`}},[e.SERVER]:{shutdownHandlers:r[e.SERVER],options:{enabledShutdownStages:[t.STOP_ACCEPTING_WORK],includeInLivenessCheck:!1,includeInReadinessCheck:!1,name:`HTTP Server`}},[e.CUSTOM]:{options:{includeInLivenessCheck:!0,includeInReadinessCheck:!0,name:`Custom Client`}}};export{i as CLIENT_DEFAULTS_MAP};
2
2
  //# sourceMappingURL=client-defaults.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"client-defaults.js","names":["CLIENT_DEFAULTS_MAP: Partial<Record<ClientType, Omit<ClientConfig, 'connection'>>>"],"sources":["../../src/health-manager/client-defaults.ts"],"sourcesContent":["import type { ClientConfig, ClientType } from './types';\nimport { CLIENT_TYPES, SHUTDOWN_STAGES } from './types';\nimport { DEFAULT_CLIENT_HEALTHCHECK_FUNC_MAP } from './health-check-handlers';\nimport { DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP } from './shutdown-handlers';\n\nexport const CLIENT_DEFAULTS_MAP: Partial<Record<ClientType, Omit<ClientConfig, 'connection'>>> = {\n [CLIENT_TYPES.RABBIT]: {\n healthCheck: DEFAULT_CLIENT_HEALTHCHECK_FUNC_MAP[CLIENT_TYPES.RABBIT],\n shutdownHandlers: DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP[CLIENT_TYPES.RABBIT],\n options: {\n shutdownStages: [SHUTDOWN_STAGES.STOP_ACCEPTING_WORK],\n includeInLivenessCheck: true,\n includeInReadinessCheck: true,\n name: 'RabbitMQ Client',\n },\n },\n [CLIENT_TYPES.SEQUELIZE]: {\n healthCheck: DEFAULT_CLIENT_HEALTHCHECK_FUNC_MAP[CLIENT_TYPES.SEQUELIZE],\n shutdownHandlers: DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP[CLIENT_TYPES.SEQUELIZE],\n options: {\n shutdownStages: [SHUTDOWN_STAGES.CLOSE],\n includeInLivenessCheck: true,\n includeInReadinessCheck: true,\n name: 'Sequelize Client',\n },\n },\n [CLIENT_TYPES.REDIS]: {\n healthCheck: DEFAULT_CLIENT_HEALTHCHECK_FUNC_MAP[CLIENT_TYPES.REDIS],\n shutdownHandlers: DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP[CLIENT_TYPES.REDIS],\n options: {\n shutdownStages: [SHUTDOWN_STAGES.CLOSE],\n includeInLivenessCheck: true,\n includeInReadinessCheck: true,\n name: 'Redis Client',\n },\n },\n [CLIENT_TYPES.ELASTIC_SEARCH]: {\n healthCheck: DEFAULT_CLIENT_HEALTHCHECK_FUNC_MAP[CLIENT_TYPES.ELASTIC_SEARCH],\n shutdownHandlers: DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP[CLIENT_TYPES.ELASTIC_SEARCH],\n options: {\n shutdownStages: [SHUTDOWN_STAGES.CLOSE],\n includeInLivenessCheck: true,\n includeInReadinessCheck: true,\n name: 'Elasticsearch Client',\n },\n },\n [CLIENT_TYPES.EVENTS]: {\n shutdownHandlers: DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP[CLIENT_TYPES.EVENTS],\n options: {\n shutdownStages: [SHUTDOWN_STAGES.CLOSE],\n includeInLivenessCheck: false,\n includeInReadinessCheck: false,\n name: 'Events Client',\n },\n },\n [CLIENT_TYPES.SERVER]: {\n shutdownHandlers: DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP[CLIENT_TYPES.SERVER],\n options: {\n shutdownStages: [SHUTDOWN_STAGES.STOP_ACCEPTING_WORK],\n includeInLivenessCheck: false,\n includeInReadinessCheck: false,\n name: 'HTTP Server',\n },\n },\n [CLIENT_TYPES.CUSTOM]: {\n options: {\n includeInLivenessCheck: true,\n includeInReadinessCheck: true,\n name: 'Custom Client',\n },\n },\n};\n"],"mappings":"8NAKA,MAAaA,EAAqF,EAC/F,EAAa,QAAS,CACrB,YAAa,EAAoC,EAAa,QAC9D,iBAAkB,EAAqC,EAAa,QACpE,QAAS,CACP,eAAgB,CAAC,EAAgB,oBAAoB,CACrD,uBAAwB,GACxB,wBAAyB,GACzB,KAAM,kBACP,CACF,EACA,EAAa,WAAY,CACxB,YAAa,EAAoC,EAAa,WAC9D,iBAAkB,EAAqC,EAAa,WACpE,QAAS,CACP,eAAgB,CAAC,EAAgB,MAAM,CACvC,uBAAwB,GACxB,wBAAyB,GACzB,KAAM,mBACP,CACF,EACA,EAAa,OAAQ,CACpB,YAAa,EAAoC,EAAa,OAC9D,iBAAkB,EAAqC,EAAa,OACpE,QAAS,CACP,eAAgB,CAAC,EAAgB,MAAM,CACvC,uBAAwB,GACxB,wBAAyB,GACzB,KAAM,eACP,CACF,EACA,EAAa,gBAAiB,CAC7B,YAAa,EAAoC,EAAa,gBAC9D,iBAAkB,EAAqC,EAAa,gBACpE,QAAS,CACP,eAAgB,CAAC,EAAgB,MAAM,CACvC,uBAAwB,GACxB,wBAAyB,GACzB,KAAM,uBACP,CACF,EACA,EAAa,QAAS,CACrB,iBAAkB,EAAqC,EAAa,QACpE,QAAS,CACP,eAAgB,CAAC,EAAgB,MAAM,CACvC,uBAAwB,GACxB,wBAAyB,GACzB,KAAM,gBACP,CACF,EACA,EAAa,QAAS,CACrB,iBAAkB,EAAqC,EAAa,QACpE,QAAS,CACP,eAAgB,CAAC,EAAgB,oBAAoB,CACrD,uBAAwB,GACxB,wBAAyB,GACzB,KAAM,cACP,CACF,EACA,EAAa,QAAS,CACrB,QAAS,CACP,uBAAwB,GACxB,wBAAyB,GACzB,KAAM,gBACP,CACF,CACF"}
1
+ {"version":3,"file":"client-defaults.js","names":["CLIENT_DEFAULTS_MAP: Partial<Record<ClientType, Omit<ClientConfig, 'connection'>>>"],"sources":["../../src/health-manager/client-defaults.ts"],"sourcesContent":["import type { ClientConfig, ClientType } from './types';\nimport { CLIENT_TYPES, SHUTDOWN_STAGES } from './types';\nimport { DEFAULT_CLIENT_HEALTHCHECK_FUNC_MAP } from './health-check-handlers';\nimport { DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP } from './shutdown-handlers';\n\nexport const CLIENT_DEFAULTS_MAP: Partial<Record<ClientType, Omit<ClientConfig, 'connection'>>> = {\n [CLIENT_TYPES.RABBIT]: {\n healthCheck: DEFAULT_CLIENT_HEALTHCHECK_FUNC_MAP[CLIENT_TYPES.RABBIT],\n shutdownHandlers: DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP[CLIENT_TYPES.RABBIT],\n options: {\n enabledShutdownStages: [SHUTDOWN_STAGES.STOP_ACCEPTING_WORK],\n includeInLivenessCheck: true,\n includeInReadinessCheck: true,\n name: 'RabbitMQ Client',\n },\n },\n [CLIENT_TYPES.SEQUELIZE]: {\n healthCheck: DEFAULT_CLIENT_HEALTHCHECK_FUNC_MAP[CLIENT_TYPES.SEQUELIZE],\n shutdownHandlers: DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP[CLIENT_TYPES.SEQUELIZE],\n options: {\n enabledShutdownStages: [SHUTDOWN_STAGES.CLOSE],\n includeInLivenessCheck: true,\n includeInReadinessCheck: true,\n name: 'Sequelize Client',\n },\n },\n [CLIENT_TYPES.REDIS]: {\n healthCheck: DEFAULT_CLIENT_HEALTHCHECK_FUNC_MAP[CLIENT_TYPES.REDIS],\n shutdownHandlers: DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP[CLIENT_TYPES.REDIS],\n options: {\n enabledShutdownStages: [SHUTDOWN_STAGES.CLOSE],\n includeInLivenessCheck: true,\n includeInReadinessCheck: true,\n name: 'Redis Client',\n },\n },\n [CLIENT_TYPES.ELASTIC_SEARCH]: {\n healthCheck: DEFAULT_CLIENT_HEALTHCHECK_FUNC_MAP[CLIENT_TYPES.ELASTIC_SEARCH],\n shutdownHandlers: DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP[CLIENT_TYPES.ELASTIC_SEARCH],\n options: {\n enabledShutdownStages: [SHUTDOWN_STAGES.CLOSE],\n includeInLivenessCheck: true,\n includeInReadinessCheck: true,\n name: 'Elasticsearch Client',\n },\n },\n [CLIENT_TYPES.EVENTS]: {\n shutdownHandlers: DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP[CLIENT_TYPES.EVENTS],\n options: {\n enabledShutdownStages: [SHUTDOWN_STAGES.CLOSE],\n includeInLivenessCheck: false,\n includeInReadinessCheck: false,\n name: 'Events Client',\n },\n },\n [CLIENT_TYPES.SERVER]: {\n shutdownHandlers: DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP[CLIENT_TYPES.SERVER],\n options: {\n enabledShutdownStages: [SHUTDOWN_STAGES.STOP_ACCEPTING_WORK],\n includeInLivenessCheck: false,\n includeInReadinessCheck: false,\n name: 'HTTP Server',\n },\n },\n [CLIENT_TYPES.CUSTOM]: {\n options: {\n includeInLivenessCheck: true,\n includeInReadinessCheck: true,\n name: 'Custom Client',\n },\n },\n};\n"],"mappings":"8NAKA,MAAaA,EAAqF,EAC/F,EAAa,QAAS,CACrB,YAAa,EAAoC,EAAa,QAC9D,iBAAkB,EAAqC,EAAa,QACpE,QAAS,CACP,sBAAuB,CAAC,EAAgB,oBAAoB,CAC5D,uBAAwB,GACxB,wBAAyB,GACzB,KAAM,kBACP,CACF,EACA,EAAa,WAAY,CACxB,YAAa,EAAoC,EAAa,WAC9D,iBAAkB,EAAqC,EAAa,WACpE,QAAS,CACP,sBAAuB,CAAC,EAAgB,MAAM,CAC9C,uBAAwB,GACxB,wBAAyB,GACzB,KAAM,mBACP,CACF,EACA,EAAa,OAAQ,CACpB,YAAa,EAAoC,EAAa,OAC9D,iBAAkB,EAAqC,EAAa,OACpE,QAAS,CACP,sBAAuB,CAAC,EAAgB,MAAM,CAC9C,uBAAwB,GACxB,wBAAyB,GACzB,KAAM,eACP,CACF,EACA,EAAa,gBAAiB,CAC7B,YAAa,EAAoC,EAAa,gBAC9D,iBAAkB,EAAqC,EAAa,gBACpE,QAAS,CACP,sBAAuB,CAAC,EAAgB,MAAM,CAC9C,uBAAwB,GACxB,wBAAyB,GACzB,KAAM,uBACP,CACF,EACA,EAAa,QAAS,CACrB,iBAAkB,EAAqC,EAAa,QACpE,QAAS,CACP,sBAAuB,CAAC,EAAgB,MAAM,CAC9C,uBAAwB,GACxB,wBAAyB,GACzB,KAAM,gBACP,CACF,EACA,EAAa,QAAS,CACrB,iBAAkB,EAAqC,EAAa,QACpE,QAAS,CACP,sBAAuB,CAAC,EAAgB,oBAAoB,CAC5D,uBAAwB,GACxB,wBAAyB,GACzB,KAAM,cACP,CACF,EACA,EAAa,QAAS,CACrB,QAAS,CACP,uBAAwB,GACxB,wBAAyB,GACzB,KAAM,gBACP,CACF,CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"health-check-handlers.cjs","names":["DEFAULT_CLIENT_HEALTHCHECK_FUNC_MAP: Partial<Record<ClientType, HealthCheckHandler>>","CLIENT_TYPES"],"sources":["../../src/health-manager/health-check-handlers.ts"],"sourcesContent":["import type {\n RedisClient,\n SequelizeClient,\n ElasticsearchClient,\n RabbitMQClient,\n ClientType,\n HealthCheckHandler,\n} from './types';\nimport { CLIENT_TYPES } from './types';\n\nconst createHealthCheckHandler = <T>(\n clientType: string,\n healthCheckHandler: (client: T) => Promise<any> | undefined,\n): HealthCheckHandler => async ({ client, name, logger }) => {\n const healthCheckFn = healthCheckHandler(client);\n if (!healthCheckFn) {\n logger.warn(`${clientType} client '${name}' does not have a health check method, skipping`);\n return;\n }\n try {\n await healthCheckFn;\n } catch (error) {\n logger.error(`${clientType} health check error for '${name}': ${error instanceof Error ? error.message : String(error)}`);\n throw error;\n }\n};\n\nexport const DEFAULT_CLIENT_HEALTHCHECK_FUNC_MAP: Partial<Record<ClientType, HealthCheckHandler>> = {\n [CLIENT_TYPES.REDIS]: createHealthCheckHandler<RedisClient>('Redis', async (client) => {\n if (!client.ping) {\n return undefined;\n }\n const result = await client.ping();\n if (result !== 'PONG') {\n throw new Error('Unexpected redis ping response');\n }\n\n return true;\n }),\n [CLIENT_TYPES.SEQUELIZE]: createHealthCheckHandler<SequelizeClient>('Sequelize', async (client) => {\n if (!client.query) {\n return undefined;\n }\n const [[result]] = await client.query('SELECT 1 as status');\n if (result?.status !== 1) {\n throw new Error('Unexpected postgres query result');\n }\n return true;\n }),\n [CLIENT_TYPES.ELASTIC_SEARCH]: createHealthCheckHandler<ElasticsearchClient>('Elasticsearch', async (client) => {\n if (!client.ping) {\n return undefined;\n }\n const isAlive = await client.ping();\n if (!isAlive) {\n throw new Error('Elasticsearch elastic ping returned false');\n }\n return true;\n }),\n [CLIENT_TYPES.RABBIT]: createHealthCheckHandler<RabbitMQClient>('RabbitMQ', async (client) => {\n if (!client.isConnected) {\n return undefined;\n }\n const isConnected = await client.isConnected();\n if (!isConnected) {\n throw new Error('RabbitMQ is not connected');\n }\n return true;\n }),\n};\n"],"mappings":"+BAUM,GACJ,EACA,IACuB,MAAO,CAAE,SAAQ,OAAM,YAAa,CAC3D,IAAM,EAAgB,EAAmB,EAAO,CAChD,GAAI,CAAC,EAAe,CAClB,EAAO,KAAK,GAAG,EAAW,WAAW,EAAK,iDAAiD,CAC3F,OAEF,GAAI,CACF,MAAM,QACC,EAAO,CAEd,MADA,EAAO,MAAM,GAAG,EAAW,2BAA2B,EAAK,KAAK,aAAiB,MAAQ,EAAM,QAAU,OAAO,EAAM,GAAG,CACnH,IAIGA,EAAuF,EACjGC,EAAAA,aAAa,OAAQ,EAAsC,QAAS,KAAO,IAAW,CAChF,KAAO,KAIZ,IADe,MAAM,EAAO,MAAM,GACnB,OACb,MAAU,MAAM,iCAAiC,CAGnD,MAAO,KACP,EACDA,EAAAA,aAAa,WAAY,EAA0C,YAAa,KAAO,IAAW,CACjG,GAAI,CAAC,EAAO,MACV,OAEF,GAAM,CAAC,CAAC,IAAW,MAAM,EAAO,MAAM,qBAAqB,CAC3D,GAAI,GAAQ,SAAW,EACrB,MAAU,MAAM,mCAAmC,CAErD,MAAO,IACP,EACDA,EAAAA,aAAa,gBAAiB,EAA8C,gBAAiB,KAAO,IAAW,CACzG,KAAO,KAIZ,IAAI,CADY,MAAM,EAAO,MAAM,CAEjC,MAAU,MAAM,4CAA4C,CAE9D,MAAO,KACP,EACDA,EAAAA,aAAa,QAAS,EAAyC,WAAY,KAAO,IAAW,CACvF,KAAO,YAIZ,IAAI,CADgB,MAAM,EAAO,aAAa,CAE5C,MAAU,MAAM,4BAA4B,CAE9C,MAAO,KACP,CACH"}
1
+ {"version":3,"file":"health-check-handlers.cjs","names":["DEFAULT_CLIENT_HEALTHCHECK_FUNC_MAP: Partial<Record<ClientType, HealthCheckHandler<any>>>","CLIENT_TYPES"],"sources":["../../src/health-manager/health-check-handlers.ts"],"sourcesContent":["import type {\n RedisClient,\n SequelizeClient,\n ElasticsearchClient,\n RabbitMQClient,\n ClientType,\n HealthCheckHandler,\n} from './types';\nimport { CLIENT_TYPES } from './types';\n\nconst createHealthCheckHandler = <T>(\n clientType: string,\n healthCheckHandler: (client: T) => Promise<any> | undefined,\n): HealthCheckHandler<T> => async ({ client, name, logger }) => {\n const healthCheckFn = healthCheckHandler(client);\n if (!healthCheckFn) {\n logger.warn(`${clientType} client '${name}' does not have a health check method, skipping`);\n return;\n }\n try {\n await healthCheckFn;\n } catch (error) {\n logger.error(`${clientType} health check error for '${name}': ${error instanceof Error ? error.message : String(error)}`);\n throw error;\n }\n};\n\nexport const DEFAULT_CLIENT_HEALTHCHECK_FUNC_MAP: Partial<Record<ClientType, HealthCheckHandler<any>>> = {\n [CLIENT_TYPES.REDIS]: createHealthCheckHandler<RedisClient>('Redis', async (client) => {\n if (!client.ping) {\n return undefined;\n }\n const result = await client.ping();\n if (result !== 'PONG') {\n throw new Error('Unexpected redis ping response');\n }\n\n return true;\n }),\n [CLIENT_TYPES.SEQUELIZE]: createHealthCheckHandler<SequelizeClient>('Sequelize', async (client) => {\n if (!client.query) {\n return undefined;\n }\n const [[result]] = await client.query('SELECT 1 as status');\n if (result?.status !== 1) {\n throw new Error('Unexpected postgres query result');\n }\n return true;\n }),\n [CLIENT_TYPES.ELASTIC_SEARCH]: createHealthCheckHandler<ElasticsearchClient>('Elasticsearch', async (client) => {\n if (!client.ping) {\n return undefined;\n }\n const isAlive = await client.ping();\n if (!isAlive) {\n throw new Error('Elasticsearch elastic ping returned false');\n }\n return true;\n }),\n [CLIENT_TYPES.RABBIT]: createHealthCheckHandler<RabbitMQClient>('RabbitMQ', async (client) => {\n if (!client.isConnected) {\n return undefined;\n }\n const isConnected = await client.isConnected();\n if (!isConnected) {\n throw new Error('RabbitMQ is not connected');\n }\n return true;\n }),\n};\n"],"mappings":"+BAUM,GACJ,EACA,IAC0B,MAAO,CAAE,SAAQ,OAAM,YAAa,CAC9D,IAAM,EAAgB,EAAmB,EAAO,CAChD,GAAI,CAAC,EAAe,CAClB,EAAO,KAAK,GAAG,EAAW,WAAW,EAAK,iDAAiD,CAC3F,OAEF,GAAI,CACF,MAAM,QACC,EAAO,CAEd,MADA,EAAO,MAAM,GAAG,EAAW,2BAA2B,EAAK,KAAK,aAAiB,MAAQ,EAAM,QAAU,OAAO,EAAM,GAAG,CACnH,IAIGA,EAA4F,EACtGC,EAAAA,aAAa,OAAQ,EAAsC,QAAS,KAAO,IAAW,CAChF,KAAO,KAIZ,IADe,MAAM,EAAO,MAAM,GACnB,OACb,MAAU,MAAM,iCAAiC,CAGnD,MAAO,KACP,EACDA,EAAAA,aAAa,WAAY,EAA0C,YAAa,KAAO,IAAW,CACjG,GAAI,CAAC,EAAO,MACV,OAEF,GAAM,CAAC,CAAC,IAAW,MAAM,EAAO,MAAM,qBAAqB,CAC3D,GAAI,GAAQ,SAAW,EACrB,MAAU,MAAM,mCAAmC,CAErD,MAAO,IACP,EACDA,EAAAA,aAAa,gBAAiB,EAA8C,gBAAiB,KAAO,IAAW,CACzG,KAAO,KAIZ,IAAI,CADY,MAAM,EAAO,MAAM,CAEjC,MAAU,MAAM,4CAA4C,CAE9D,MAAO,KACP,EACDA,EAAAA,aAAa,QAAS,EAAyC,WAAY,KAAO,IAAW,CACvF,KAAO,YAIZ,IAAI,CADgB,MAAM,EAAO,aAAa,CAE5C,MAAU,MAAM,4BAA4B,CAE9C,MAAO,KACP,CACH"}
@@ -1 +1 @@
1
- {"version":3,"file":"health-check-handlers.js","names":["DEFAULT_CLIENT_HEALTHCHECK_FUNC_MAP: Partial<Record<ClientType, HealthCheckHandler>>"],"sources":["../../src/health-manager/health-check-handlers.ts"],"sourcesContent":["import type {\n RedisClient,\n SequelizeClient,\n ElasticsearchClient,\n RabbitMQClient,\n ClientType,\n HealthCheckHandler,\n} from './types';\nimport { CLIENT_TYPES } from './types';\n\nconst createHealthCheckHandler = <T>(\n clientType: string,\n healthCheckHandler: (client: T) => Promise<any> | undefined,\n): HealthCheckHandler => async ({ client, name, logger }) => {\n const healthCheckFn = healthCheckHandler(client);\n if (!healthCheckFn) {\n logger.warn(`${clientType} client '${name}' does not have a health check method, skipping`);\n return;\n }\n try {\n await healthCheckFn;\n } catch (error) {\n logger.error(`${clientType} health check error for '${name}': ${error instanceof Error ? error.message : String(error)}`);\n throw error;\n }\n};\n\nexport const DEFAULT_CLIENT_HEALTHCHECK_FUNC_MAP: Partial<Record<ClientType, HealthCheckHandler>> = {\n [CLIENT_TYPES.REDIS]: createHealthCheckHandler<RedisClient>('Redis', async (client) => {\n if (!client.ping) {\n return undefined;\n }\n const result = await client.ping();\n if (result !== 'PONG') {\n throw new Error('Unexpected redis ping response');\n }\n\n return true;\n }),\n [CLIENT_TYPES.SEQUELIZE]: createHealthCheckHandler<SequelizeClient>('Sequelize', async (client) => {\n if (!client.query) {\n return undefined;\n }\n const [[result]] = await client.query('SELECT 1 as status');\n if (result?.status !== 1) {\n throw new Error('Unexpected postgres query result');\n }\n return true;\n }),\n [CLIENT_TYPES.ELASTIC_SEARCH]: createHealthCheckHandler<ElasticsearchClient>('Elasticsearch', async (client) => {\n if (!client.ping) {\n return undefined;\n }\n const isAlive = await client.ping();\n if (!isAlive) {\n throw new Error('Elasticsearch elastic ping returned false');\n }\n return true;\n }),\n [CLIENT_TYPES.RABBIT]: createHealthCheckHandler<RabbitMQClient>('RabbitMQ', async (client) => {\n if (!client.isConnected) {\n return undefined;\n }\n const isConnected = await client.isConnected();\n if (!isConnected) {\n throw new Error('RabbitMQ is not connected');\n }\n return true;\n }),\n};\n"],"mappings":"0CAUA,MAAM,GACJ,EACA,IACuB,MAAO,CAAE,SAAQ,OAAM,YAAa,CAC3D,IAAM,EAAgB,EAAmB,EAAO,CAChD,GAAI,CAAC,EAAe,CAClB,EAAO,KAAK,GAAG,EAAW,WAAW,EAAK,iDAAiD,CAC3F,OAEF,GAAI,CACF,MAAM,QACC,EAAO,CAEd,MADA,EAAO,MAAM,GAAG,EAAW,2BAA2B,EAAK,KAAK,aAAiB,MAAQ,EAAM,QAAU,OAAO,EAAM,GAAG,CACnH,IAIGA,EAAuF,EACjG,EAAa,OAAQ,EAAsC,QAAS,KAAO,IAAW,CAChF,KAAO,KAIZ,IADe,MAAM,EAAO,MAAM,GACnB,OACb,MAAU,MAAM,iCAAiC,CAGnD,MAAO,KACP,EACD,EAAa,WAAY,EAA0C,YAAa,KAAO,IAAW,CACjG,GAAI,CAAC,EAAO,MACV,OAEF,GAAM,CAAC,CAAC,IAAW,MAAM,EAAO,MAAM,qBAAqB,CAC3D,GAAI,GAAQ,SAAW,EACrB,MAAU,MAAM,mCAAmC,CAErD,MAAO,IACP,EACD,EAAa,gBAAiB,EAA8C,gBAAiB,KAAO,IAAW,CACzG,KAAO,KAIZ,IAAI,CADY,MAAM,EAAO,MAAM,CAEjC,MAAU,MAAM,4CAA4C,CAE9D,MAAO,KACP,EACD,EAAa,QAAS,EAAyC,WAAY,KAAO,IAAW,CACvF,KAAO,YAIZ,IAAI,CADgB,MAAM,EAAO,aAAa,CAE5C,MAAU,MAAM,4BAA4B,CAE9C,MAAO,KACP,CACH"}
1
+ {"version":3,"file":"health-check-handlers.js","names":["DEFAULT_CLIENT_HEALTHCHECK_FUNC_MAP: Partial<Record<ClientType, HealthCheckHandler<any>>>"],"sources":["../../src/health-manager/health-check-handlers.ts"],"sourcesContent":["import type {\n RedisClient,\n SequelizeClient,\n ElasticsearchClient,\n RabbitMQClient,\n ClientType,\n HealthCheckHandler,\n} from './types';\nimport { CLIENT_TYPES } from './types';\n\nconst createHealthCheckHandler = <T>(\n clientType: string,\n healthCheckHandler: (client: T) => Promise<any> | undefined,\n): HealthCheckHandler<T> => async ({ client, name, logger }) => {\n const healthCheckFn = healthCheckHandler(client);\n if (!healthCheckFn) {\n logger.warn(`${clientType} client '${name}' does not have a health check method, skipping`);\n return;\n }\n try {\n await healthCheckFn;\n } catch (error) {\n logger.error(`${clientType} health check error for '${name}': ${error instanceof Error ? error.message : String(error)}`);\n throw error;\n }\n};\n\nexport const DEFAULT_CLIENT_HEALTHCHECK_FUNC_MAP: Partial<Record<ClientType, HealthCheckHandler<any>>> = {\n [CLIENT_TYPES.REDIS]: createHealthCheckHandler<RedisClient>('Redis', async (client) => {\n if (!client.ping) {\n return undefined;\n }\n const result = await client.ping();\n if (result !== 'PONG') {\n throw new Error('Unexpected redis ping response');\n }\n\n return true;\n }),\n [CLIENT_TYPES.SEQUELIZE]: createHealthCheckHandler<SequelizeClient>('Sequelize', async (client) => {\n if (!client.query) {\n return undefined;\n }\n const [[result]] = await client.query('SELECT 1 as status');\n if (result?.status !== 1) {\n throw new Error('Unexpected postgres query result');\n }\n return true;\n }),\n [CLIENT_TYPES.ELASTIC_SEARCH]: createHealthCheckHandler<ElasticsearchClient>('Elasticsearch', async (client) => {\n if (!client.ping) {\n return undefined;\n }\n const isAlive = await client.ping();\n if (!isAlive) {\n throw new Error('Elasticsearch elastic ping returned false');\n }\n return true;\n }),\n [CLIENT_TYPES.RABBIT]: createHealthCheckHandler<RabbitMQClient>('RabbitMQ', async (client) => {\n if (!client.isConnected) {\n return undefined;\n }\n const isConnected = await client.isConnected();\n if (!isConnected) {\n throw new Error('RabbitMQ is not connected');\n }\n return true;\n }),\n};\n"],"mappings":"0CAUA,MAAM,GACJ,EACA,IAC0B,MAAO,CAAE,SAAQ,OAAM,YAAa,CAC9D,IAAM,EAAgB,EAAmB,EAAO,CAChD,GAAI,CAAC,EAAe,CAClB,EAAO,KAAK,GAAG,EAAW,WAAW,EAAK,iDAAiD,CAC3F,OAEF,GAAI,CACF,MAAM,QACC,EAAO,CAEd,MADA,EAAO,MAAM,GAAG,EAAW,2BAA2B,EAAK,KAAK,aAAiB,MAAQ,EAAM,QAAU,OAAO,EAAM,GAAG,CACnH,IAIGA,EAA4F,EACtG,EAAa,OAAQ,EAAsC,QAAS,KAAO,IAAW,CAChF,KAAO,KAIZ,IADe,MAAM,EAAO,MAAM,GACnB,OACb,MAAU,MAAM,iCAAiC,CAGnD,MAAO,KACP,EACD,EAAa,WAAY,EAA0C,YAAa,KAAO,IAAW,CACjG,GAAI,CAAC,EAAO,MACV,OAEF,GAAM,CAAC,CAAC,IAAW,MAAM,EAAO,MAAM,qBAAqB,CAC3D,GAAI,GAAQ,SAAW,EACrB,MAAU,MAAM,mCAAmC,CAErD,MAAO,IACP,EACD,EAAa,gBAAiB,EAA8C,gBAAiB,KAAO,IAAW,CACzG,KAAO,KAIZ,IAAI,CADY,MAAM,EAAO,MAAM,CAEjC,MAAU,MAAM,4CAA4C,CAE9D,MAAO,KACP,EACD,EAAa,QAAS,EAAyC,WAAY,KAAO,IAAW,CACvF,KAAO,YAIZ,IAAI,CADgB,MAAM,EAAO,aAAa,CAE5C,MAAU,MAAM,4BAA4B,CAE9C,MAAO,KACP,CACH"}
@@ -1,2 +1,2 @@
1
- const e=require(`../_virtual/rolldown_runtime.cjs`),t=require(`./types.cjs`),n=require(`./client-defaults.cjs`);let r=require(`node:timers/promises`),i=require(`@autofleet/errors`),a=require(`http-terminator`);var o=class{constructor(e){this.DEFAULT_CONFIG={shutdownDelayMs:8e3,useExit0:!0,shouldSetupSignalHandlers:!0,enableLivenessOptimization:!0},this.isShuttingDown=!1,this.isReady=!1,this.clientsMap=new Map,this.livenessChecks=[],this.readinessChecks=[],this.canSafelySkipLivenessWhenReady=(e,t)=>e?!!t:!0,this.config={...this.DEFAULT_CONFIG,...e.config??{}},this.logger=e.logger,this.storeClientsWithDefaults(e),this.initializeHealthChecks(),this.config.shouldSetupSignalHandlers&&this.setupSignalHandlers()}storeClientsWithDefaults(e){let r=e.clients;if(r){for(let[e,i]of Object.entries(r))if(i)if(e===t.CLIENT_TYPES.SERVER)this.attachServer(i);else{let r=Array.isArray(i)?i:[i],a=n.CLIENT_DEFAULTS_MAP[e]??n.CLIENT_DEFAULTS_MAP[t.CLIENT_TYPES.CUSTOM],o=r.map(t=>({connection:t.connection,healthCheck:t.healthCheck??a?.healthCheck,shutdownHandlers:{...a?.shutdownHandlers,...t.shutdownHandlers},options:{...a?.options,...t.options,name:t.options?.name||a?.options?.name||e}}));this.clientsMap.set(e,o)}}}setupSignalHandlers(){this.logger.info(`Setting up global signal listeners for graceful shutdown`),process.on(`SIGTERM`,async()=>{await this.shutdown(`SIGTERM`)}),process.on(`SIGINT`,async()=>{await this.shutdown(`SIGINT`)})}initializeHealthChecks(){let e=!0;this.clientsMap.forEach(t=>{t.forEach(t=>{if(!t.healthCheck)return;let n=t.options?.includeInLivenessCheck,r=t.options?.includeInReadinessCheck;this.canSafelySkipLivenessWhenReady(n,r)||(e=!1),n&&this.livenessChecks.push({check:t.healthCheck,client:t.connection,name:t.options?.name||`unknown`,customHandlersPayload:t.options?.customHandlersPayload}),r&&this.readinessChecks.push({check:t.healthCheck,client:t.connection,name:t.options?.name||`unknown`,customHandlersPayload:t.options?.customHandlersPayload})})}),this.config.enableLivenessOptimization=this.config.enableLivenessOptimization&&e,this.config.enableLivenessOptimization?this.logger.info(`Liveness check optimization enabled - liveness checks will be skipped when pod is ready`):e||this.logger.warn(`Liveness check optimization disabled - some clients are in liveness checks but not in readiness checks`)}attachServer(e){let r=n.CLIENT_DEFAULTS_MAP[t.CLIENT_TYPES.SERVER],i=(Array.isArray(e)?e:[e]).map(e=>{let t=(0,a.createHttpTerminator)({server:e.connection});return{connection:e.connection,healthCheck:e.healthCheck??r?.healthCheck,shutdownHandlers:{...r?.shutdownHandlers,...e.shutdownHandlers},options:{...r?.options,...e.options,name:e.options?.name||r?.options?.name||`HTTP Server`,customHandlersPayload:{...e.options?.customHandlersPayload,httpTerminator:t}}}});this.clientsMap.set(t.CLIENT_TYPES.SERVER,i)}async aliveCheck(){if(this.isShuttingDown||this.config.enableLivenessOptimization&&this.isReady)return{statusCode:200,status:`ok`};try{return await Promise.all(this.livenessChecks.map(({check:e,client:t,name:n,customHandlersPayload:r})=>e({client:t,name:n,customHandlersPayload:r,logger:this.logger}))),{statusCode:200,status:`ok`}}catch(e){let t=new i.ServiceUnavailableError(`Liveness probe failed: ${e.message}`);throw t.stack=e.stack,t}}async readyCheck(){if(this.isShuttingDown)throw this.isReady=!1,new i.ServiceUnavailableError(`Readiness probe failed: Application is shutting down`);try{return await Promise.all(this.readinessChecks.map(({check:e,client:t,name:n,customHandlersPayload:r})=>e({client:t,name:n,customHandlersPayload:r,logger:this.logger}))),this.isReady=!0,{statusCode:200,status:`ok`}}catch(e){this.isReady=!1;let t=new i.ServiceUnavailableError(`Readiness probe failed: ${e.message}`);throw t.stack=e.stack,t}}groupShutdownTasksByStage(e){let n={[t.SHUTDOWN_STAGES.STOP_ACCEPTING_WORK]:[],[t.SHUTDOWN_STAGES.DRAIN]:[],[t.SHUTDOWN_STAGES.CLOSE]:[]};return this.clientsMap.forEach(t=>{t.forEach(t=>{let r=t.options?.name||`unknown`,i=t.options?.shutdownStages;if(t.shutdownHandlers)for(let[a,o]of Object.entries(t.shutdownHandlers))o&&i?.includes(a)&&n[a].push({fn:()=>o({signal:e,client:t.connection,name:r,customHandlersPayload:t.options?.customHandlersPayload,logger:this.logger}),name:r})})}),n}async executeShutdownStage(e,t){t.length!==0&&(this.logger.info(`[${e} stage] Start executing shutdown...`),(await Promise.allSettled(t.map(e=>e.fn()))).forEach((n,r)=>{if(n.status===`rejected`){let{name:i}=t[r];this.logger.error(`[${e} stage] Failed to shutdown '${i}'`,{error:n.reason})}}),this.logger.info(`[${e} stage] Shutdown completed`))}async shutdown(e=`MANUAL`){try{if(this.isShuttingDown){this.logger.warn(`Shutdown already in progress`);return}let{shutdownDelayMs:n,useExit0:i,onShutdown:a,beforeShutdown:o}=this.config;this.logger.info(`${e} received: setting readiness state to false`),this.isShuttingDown=!0,this.isReady=!1,await o?.(),this.logger.info(`Waiting ${n}ms before shutdown...`),await(0,r.setTimeout)(n);let s=this.groupShutdownTasksByStage(e);await this.executeShutdownStage(t.SHUTDOWN_STAGES.STOP_ACCEPTING_WORK,s[t.SHUTDOWN_STAGES.STOP_ACCEPTING_WORK]),this.logger.info(`Waiting 2000ms to allow in-flight work to complete...`),await(0,r.setTimeout)(2e3),await this.executeShutdownStage(t.SHUTDOWN_STAGES.DRAIN,s[t.SHUTDOWN_STAGES.DRAIN]),await this.executeShutdownStage(t.SHUTDOWN_STAGES.CLOSE,s[t.SHUTDOWN_STAGES.CLOSE]),await a?.(),this.logger.info(`Shutdown process completed`),i&&(this.logger.info(`Exiting process after ${e}`),process.exit(0))}catch(t){this.logger.error(`Error during shutdown process, forcing process exit despite shutdown error`,{error:t,signal:e}),process.exit(1)}}};exports.HealthManager=o;
1
+ const e=require(`../_virtual/rolldown_runtime.cjs`),t=require(`./types.cjs`),n=require(`./client-defaults.cjs`);let r=require(`node:timers/promises`),i=require(`@autofleet/errors`),a=require(`http-terminator`);var o=class{constructor(e){this.DEFAULT_CONFIG={shutdownDelayMs:8e3,useExit0:!0,shouldSetupSignalHandlers:!0,enableLivenessOptimization:!0},this.isShuttingDown=!1,this.isReady=!1,this.clientsMap=new Map,this.livenessChecks=[],this.readinessChecks=[],this.canSafelySkipLivenessWhenReady=(e,t)=>e?!!t:!0,this.config={...this.DEFAULT_CONFIG,...e.config??{}},this.logger=e.logger,this.storeClientsWithDefaults(e),this.initializeHealthChecks(),this.config.shouldSetupSignalHandlers&&this.setupSignalHandlers()}storeClientsWithDefaults(e){let r=e.clients;if(r){for(let[e,i]of Object.entries(r))if(i)if(e===t.CLIENT_TYPES.SERVER)this.attachServer(i);else{let r=Array.isArray(i)?i:[i],a=n.CLIENT_DEFAULTS_MAP[e]??n.CLIENT_DEFAULTS_MAP[t.CLIENT_TYPES.CUSTOM],o=r.map(t=>({connection:t.connection,healthCheck:t.healthCheck??a?.healthCheck,shutdownHandlers:{...a?.shutdownHandlers,...t.shutdownHandlers},options:{...a?.options,...t.options,name:t.options?.name||a?.options?.name||e}}));this.clientsMap.set(e,o)}}}setupSignalHandlers(){this.logger.info(`Setting up global signal listeners for graceful shutdown`),process.on(`SIGTERM`,async()=>{await this.shutdown(`SIGTERM`)}),process.on(`SIGINT`,async()=>{await this.shutdown(`SIGINT`)})}initializeHealthChecks(){let e=!0;this.clientsMap.forEach(t=>{t.forEach(t=>{if(!t.healthCheck)return;let n=t.options?.includeInLivenessCheck,r=t.options?.includeInReadinessCheck;this.canSafelySkipLivenessWhenReady(n,r)||(e=!1),n&&this.livenessChecks.push({check:t.healthCheck,client:t.connection,name:t.options?.name||`unknown`,customHandlersPayload:t.options?.customHandlersPayload}),r&&this.readinessChecks.push({check:t.healthCheck,client:t.connection,name:t.options?.name||`unknown`,customHandlersPayload:t.options?.customHandlersPayload})})}),this.config.enableLivenessOptimization=this.config.enableLivenessOptimization&&e,this.config.enableLivenessOptimization?this.logger.info(`Liveness check optimization enabled - liveness checks will be skipped when pod is ready`):e||this.logger.warn(`Liveness check optimization disabled - some clients are in liveness checks but not in readiness checks`)}attachServer(e){let r=n.CLIENT_DEFAULTS_MAP[t.CLIENT_TYPES.SERVER],i=(Array.isArray(e)?e:[e]).map(e=>{let t=(0,a.createHttpTerminator)({server:e.connection});return{connection:e.connection,healthCheck:e.healthCheck??r?.healthCheck,shutdownHandlers:{...r?.shutdownHandlers,...e.shutdownHandlers},options:{...r?.options,...e.options,name:e.options?.name||r?.options?.name||`HTTP Server`,customHandlersPayload:{...e.options?.customHandlersPayload,httpTerminator:t}}}});this.clientsMap.set(t.CLIENT_TYPES.SERVER,i)}async aliveCheck(){if(this.isShuttingDown||this.config.enableLivenessOptimization&&this.isReady)return{statusCode:200,status:`ok`};try{return await Promise.all(this.livenessChecks.map(({check:e,client:t,name:n,customHandlersPayload:r})=>e({client:t,name:n,customHandlersPayload:r,logger:this.logger}))),{statusCode:200,status:`ok`}}catch(e){let t=new i.ServiceUnavailableError(`Liveness probe failed: ${e.message}`);throw t.stack=e.stack,t}}async readyCheck(){if(this.isShuttingDown)throw this.isReady=!1,this.logger.warn(`Application is shutting down: readiness probe failed`),new i.ServiceUnavailableError(`Readiness probe failed: Application is shutting down`);try{return await Promise.all(this.readinessChecks.map(({check:e,client:t,name:n,customHandlersPayload:r})=>e({client:t,name:n,customHandlersPayload:r,logger:this.logger}))),this.isReady=!0,{statusCode:200,status:`ok`}}catch(e){this.isReady=!1;let t=new i.ServiceUnavailableError(`Readiness probe failed: ${e.message}`);throw t.stack=e.stack,t}}groupShutdownTasksByStage(e){let n={[t.SHUTDOWN_STAGES.STOP_ACCEPTING_WORK]:[],[t.SHUTDOWN_STAGES.DRAIN]:[],[t.SHUTDOWN_STAGES.CLOSE]:[]};return this.clientsMap.forEach(t=>{t.forEach(t=>{let r=t.options?.name||`unknown`,i=t.options?.enabledShutdownStages;if(t.shutdownHandlers)for(let[a,o]of Object.entries(t.shutdownHandlers))o&&i?.includes(a)&&n[a].push({fn:()=>o({signal:e,client:t.connection,name:r,customHandlersPayload:t.options?.customHandlersPayload,logger:this.logger}),name:r})})}),n}async executeShutdownStage(e,t){t.length!==0&&(this.logger.info(`[${e} stage] Start executing shutdown stage ${e}...`),(await Promise.allSettled(t.map(e=>e.fn()))).forEach((n,r)=>{if(n.status===`rejected`){let{name:i}=t[r];this.logger.error(`[${e} stage] Failed to shutdown '${i}'`,{error:n.reason})}}),this.logger.info(`[${e} stage] Shutdown stage ${e} completed`))}async shutdown(e=`MANUAL`){try{if(this.isShuttingDown){this.logger.warn(`Shutdown already in progress`);return}let{shutdownDelayMs:n,useExit0:i,onShutdown:a,beforeShutdown:o}=this.config;this.logger.info(`${e} received: setting readiness state to false`),this.isShuttingDown=!0,this.isReady=!1,await o?.(),this.logger.info(`Waiting ${n}ms before shutdown...`),await(0,r.setTimeout)(n);let s=this.groupShutdownTasksByStage(e);await this.executeShutdownStage(t.SHUTDOWN_STAGES.STOP_ACCEPTING_WORK,s[t.SHUTDOWN_STAGES.STOP_ACCEPTING_WORK]),this.logger.info(`Waiting 2000ms to allow in-flight work to complete...`),await(0,r.setTimeout)(2e3),await this.executeShutdownStage(t.SHUTDOWN_STAGES.DRAIN,s[t.SHUTDOWN_STAGES.DRAIN]),await this.executeShutdownStage(t.SHUTDOWN_STAGES.CLOSE,s[t.SHUTDOWN_STAGES.CLOSE]),await a?.(),this.logger.info(`Shutdown process completed`),i&&(this.logger.info(`Exiting process after ${e}`),process.exit(0))}catch(t){this.logger.error(`Error during shutdown process, forcing process exit despite shutdown error`,{error:t,signal:e}),process.exit(1)}}};exports.HealthManager=o;
2
2
  //# sourceMappingURL=health-manager.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"health-manager.cjs","names":["CLIENT_TYPES","CLIENT_DEFAULTS_MAP","client","error: any","ServiceUnavailableError","shutdownTasksByStage: Record<ShutdownStage, { fn: () => Promise<any>; name: string; }[]>","SHUTDOWN_STAGES"],"sources":["../../src/health-manager/health-manager.ts"],"sourcesContent":["import { setTimeout } from 'node:timers/promises';\nimport { ServiceUnavailableError } from '@autofleet/errors';\nimport type { LoggerInstanceManager } from '@autofleet/logger';\nimport { createHttpTerminator } from 'http-terminator';\nimport {\n type ClientConfig,\n type HealthManagerConfig,\n type HealthManagerOptions,\n type ClientType,\n type HealthCheckHandler,\n type ShutdownStage,\n type ServerConfig,\n CLIENT_TYPES,\n SHUTDOWN_STAGES,\n type ShutdownHandler,\n} from './types';\nimport { CLIENT_DEFAULTS_MAP } from './client-defaults';\n\n/**\n * Manages application health state and graceful shutdown for Kubernetes liveness/readiness probes\n *\n * Features:\n * - Provides aliveCheck() and readyCheck() methods for liveness/readiness probes\n * - Auto-registers SIGTERM/SIGINT handlers for graceful shutdown\n * - Manages ready state during shutdown to fail readiness probes\n */\nexport class HealthManager {\n private readonly DEFAULT_CONFIG: HealthManagerConfig = {\n shutdownDelayMs: 8_000,\n useExit0: true,\n shouldSetupSignalHandlers: true,\n enableLivenessOptimization: true,\n };\n\n private isShuttingDown = false;\n private isReady = false;\n\n private config: HealthManagerConfig;\n\n private clientsMap = new Map<string, ClientConfig<any>[]>();\n\n private livenessChecks: { check: HealthCheckHandler; client: any; name: string; customHandlersPayload?: any; }[] = [];\n private readinessChecks: { check: HealthCheckHandler; client: any; name: string; customHandlersPayload?: any; }[] = [];\n\n private logger: LoggerInstanceManager;\n\n /**\n * Creates a new HealthManager instance\n *\n * @param params Configuration options for health checks and shutdown behavior\n */\n constructor(params: HealthManagerOptions) {\n this.config = {\n ...this.DEFAULT_CONFIG,\n ...(params.config ?? {}),\n };\n\n this.logger = params.logger;\n\n this.storeClientsWithDefaults(params);\n\n this.initializeHealthChecks();\n\n if (this.config.shouldSetupSignalHandlers) {\n this.setupSignalHandlers();\n }\n }\n\n /**\n * Store clients with default health check and shutdown functions\n * @private\n */\n private storeClientsWithDefaults(params: HealthManagerOptions): void {\n const clients = params.clients;\n if (!clients) {\n return;\n }\n\n for (const [type, client] of Object.entries(clients)) {\n if (!client) {\n continue;\n }\n\n if (type === CLIENT_TYPES.SERVER) {\n this.attachServer(client);\n } else {\n const clientsArray = Array.isArray(client) ? client : [client];\n const defaults = CLIENT_DEFAULTS_MAP[type as ClientType] ?? CLIENT_DEFAULTS_MAP[CLIENT_TYPES.CUSTOM];\n\n const clientsWithDefaults = clientsArray.map(client => ({\n connection: client.connection,\n healthCheck: client.healthCheck ?? defaults?.healthCheck,\n shutdownHandlers: {\n ...defaults?.shutdownHandlers,\n ...client.shutdownHandlers,\n },\n options: {\n ...defaults?.options,\n ...client.options,\n name: client.options?.name || defaults?.options?.name || type,\n },\n }));\n\n this.clientsMap.set(type, clientsWithDefaults);\n }\n }\n }\n\n /**\n * Register SIGTERM and SIGINT signal listeners\n * @private\n */\n private setupSignalHandlers(): void {\n this.logger.info('Setting up global signal listeners for graceful shutdown');\n\n process.on('SIGTERM', async () => {\n await this.shutdown('SIGTERM');\n });\n\n process.on('SIGINT', async () => {\n await this.shutdown('SIGINT');\n });\n }\n\n /**\n * Check if liveness optimization is safe to enable for a given client configuration\n * If a client is in liveness but not readiness, we cannot skip liveness checks\n * because the optimization relies on readiness passing, but this client isn't checked in readiness\n * @private\n */\n private canSafelySkipLivenessWhenReady = (includeInLiveness: boolean | undefined, includeInReadiness: boolean | undefined): boolean => {\n // If not in liveness, optimization is safe (not affected)\n if (!includeInLiveness) {\n return true;\n }\n\n // If in liveness, must also be in readiness for optimization to be safe\n return !!includeInReadiness;\n };\n\n /**\n * Initialize health check arrays based on configured clients\n * @private\n */\n private initializeHealthChecks(): void {\n let allClientsAllowLivenessOptimization = true;\n\n this.clientsMap.forEach((clients) => {\n clients.forEach((client) => {\n if (!client.healthCheck) {\n return;\n }\n\n const includeInLiveness = client.options?.includeInLivenessCheck;\n const includeInReadiness = client.options?.includeInReadinessCheck;\n\n // Check if this client configuration allows liveness optimization\n if (!this.canSafelySkipLivenessWhenReady(includeInLiveness, includeInReadiness)) {\n allClientsAllowLivenessOptimization = false;\n }\n\n if (includeInLiveness) {\n this.livenessChecks.push({\n check: client.healthCheck,\n client: client.connection,\n name: client.options?.name || 'unknown',\n customHandlersPayload: client.options?.customHandlersPayload,\n });\n }\n\n if (includeInReadiness) {\n this.readinessChecks.push({\n check: client.healthCheck,\n client: client.connection,\n name: client.options?.name || 'unknown',\n customHandlersPayload: client.options?.customHandlersPayload,\n });\n }\n });\n });\n\n // Apply optimization setting: only enable if user requested it AND all clients allow it\n this.config.enableLivenessOptimization = this.config.enableLivenessOptimization && allClientsAllowLivenessOptimization;\n\n // Log optimization status\n if (this.config.enableLivenessOptimization) {\n this.logger.info('Liveness check optimization enabled - liveness checks will be skipped when pod is ready');\n } else if (!allClientsAllowLivenessOptimization) {\n this.logger.warn('Liveness check optimization disabled - some clients are in liveness checks but not in readiness checks');\n }\n }\n\n /**\n * Attach an HTTP or HTTPS server (or multiple servers) to be managed during shutdown\n * @param serverConfig Server configuration (ClientConfig with HTTP/HTTPS server) - can be a single config or array of configs\n */\n attachServer(serverConfig: ServerConfig | ServerConfig[]): void {\n const serverDefaults = CLIENT_DEFAULTS_MAP[CLIENT_TYPES.SERVER];\n const serverConfigArray = Array.isArray(serverConfig) ? serverConfig : [serverConfig];\n\n const serverClients = serverConfigArray.map((config) => {\n // Create httpTerminator for this server instance\n const httpTerminator = createHttpTerminator({\n server: config.connection,\n });\n\n return {\n connection: config.connection,\n healthCheck: config.healthCheck ?? serverDefaults?.healthCheck,\n shutdownHandlers: {\n ...serverDefaults?.shutdownHandlers,\n ...config.shutdownHandlers,\n },\n options: {\n ...serverDefaults?.options,\n ...config.options,\n name: config.options?.name || serverDefaults?.options?.name || 'HTTP Server',\n customHandlersPayload: {\n ...config.options?.customHandlersPayload,\n httpTerminator,\n },\n },\n };\n });\n\n this.clientsMap.set(CLIENT_TYPES.SERVER, serverClients);\n }\n\n /**\n * Performs liveness health checks for clients configured with includeInLivenessCheck\n *\n * @returns Promise that resolves to { status: 'ok', statusCode: 200 } on success\n * @throws ServiceUnavailableError with statusCode 503 if any health check fails\n */\n async aliveCheck(): Promise<{ status: string; statusCode: number; }> {\n if (this.isShuttingDown) {\n return { statusCode: 200, status: 'ok' };\n }\n\n // Skip liveness check if optimization is enabled and the readiness check has already passed\n if (this.config.enableLivenessOptimization && this.isReady) {\n return { statusCode: 200, status: 'ok' };\n }\n\n try {\n await Promise.all(\n this.livenessChecks.map(({ check, client, name, customHandlersPayload }) =>\n check({ client, name, customHandlersPayload, logger: this.logger }),\n ),\n );\n\n return { statusCode: 200, status: 'ok' };\n } catch (error: any) {\n const err = new ServiceUnavailableError(`Liveness probe failed: ${error.message}`);\n err.stack = error.stack;\n throw err;\n }\n }\n\n /**\n * Performs readiness health checks for clients configured with includeInReadinessCheck\n *\n * @returns Promise that resolves to { status: 'ok', statusCode: 200 } if ready\n * @throws ServiceUnavailableError with statusCode 503 if not ready or health check fails\n */\n async readyCheck(): Promise<{ status: string; statusCode: number; }> {\n if (this.isShuttingDown) {\n this.isReady = false;\n throw new ServiceUnavailableError('Readiness probe failed: Application is shutting down');\n }\n\n try {\n await Promise.all(\n this.readinessChecks.map(({ check, client, name, customHandlersPayload }) =>\n check({ client, name, customHandlersPayload, logger: this.logger }),\n ),\n );\n this.isReady = true;\n\n return { statusCode: 200, status: 'ok' };\n } catch (error: any) {\n this.isReady = false;\n const err = new ServiceUnavailableError(`Readiness probe failed: ${error.message}`);\n err.stack = error.stack;\n throw err;\n }\n }\n\n /**\n * Groups client shutdown handlers by stage (stopAcceptingWork, drain, close).\n * Only includes handlers for stages each client has configured via shutdownStages.\n *\n * @private\n * @param signal - Signal name to pass to shutdown handlers\n * @returns Record of shutdown tasks organized by stage\n */\n private groupShutdownTasksByStage(signal: string): Record<ShutdownStage, { fn: () => Promise<any>; name: string; }[]> {\n const shutdownTasksByStage: Record<ShutdownStage, { fn: () => Promise<any>; name: string; }[]> = {\n [SHUTDOWN_STAGES.STOP_ACCEPTING_WORK]: [],\n [SHUTDOWN_STAGES.DRAIN]: [],\n [SHUTDOWN_STAGES.CLOSE]: [],\n };\n\n this.clientsMap.forEach((clients) => {\n clients.forEach((client) => {\n const clientName = client.options?.name || 'unknown';\n const configuredShutdownStages = client.options?.shutdownStages;\n\n if (client.shutdownHandlers) {\n for (const [stage, shutdownHandler] of Object.entries(client.shutdownHandlers) as [ShutdownStage, ShutdownHandler][]) {\n if (shutdownHandler && configuredShutdownStages?.includes(stage)) {\n shutdownTasksByStage[stage].push({\n fn: () => shutdownHandler({\n signal,\n client: client.connection,\n name: clientName,\n customHandlersPayload: client.options?.customHandlersPayload,\n logger: this.logger,\n }),\n name: clientName,\n });\n }\n }\n }\n });\n });\n\n return shutdownTasksByStage;\n }\n\n /**\n * Execute shutdown tasks for a specific stage\n * @private\n * @param stage - The shutdown stage to execute\n * @param tasks - Array of shutdown tasks to execute\n */\n private async executeShutdownStage(stage: ShutdownStage, tasks: { fn: () => Promise<any>; name: string; }[]): Promise<void> {\n if (tasks.length === 0) {\n return;\n }\n\n this.logger.info(`[${stage} stage] Start executing shutdown...`);\n const results = await Promise.allSettled(tasks.map(t => t.fn()));\n results.forEach((result, index) => {\n if (result.status === 'rejected') {\n const { name } = tasks[index];\n this.logger.error(`[${stage} stage] Failed to shutdown '${name}'`, { error: result.reason });\n }\n });\n this.logger.info(`[${stage} stage] Shutdown completed`);\n }\n\n /**\n * Triggers graceful shutdown process\n * Can be called manually or automatically via SIGTERM/SIGINT signal handlers\n *\n * Shutdown happens in three stages:\n * 1. stopAcceptingWork - Stop accepting new requests/work\n * 2. drain - Allow in-flight work to complete\n * 3. close - Close all connections and clean up resources\n *\n * @param signal - Signal name (e.g., 'SIGTERM', 'SIGINT', 'MANUAL')\n */\n async shutdown(signal = 'MANUAL'): Promise<void> {\n try {\n if (this.isShuttingDown) {\n this.logger.warn('Shutdown already in progress');\n return;\n }\n\n const { shutdownDelayMs, useExit0, onShutdown, beforeShutdown } = this.config;\n\n this.logger.info(`${signal} received: setting readiness state to false`);\n\n this.isShuttingDown = true;\n this.isReady = false;\n\n await beforeShutdown?.();\n\n this.logger.info(`Waiting ${shutdownDelayMs}ms before shutdown...`);\n await setTimeout(shutdownDelayMs);\n\n const shutdownTasksByStage = this.groupShutdownTasksByStage(signal);\n\n await this.executeShutdownStage(SHUTDOWN_STAGES.STOP_ACCEPTING_WORK, shutdownTasksByStage[SHUTDOWN_STAGES.STOP_ACCEPTING_WORK]);\n\n // Wait between stages to allow in-flight work to complete (we are missing a drain stage in our rabbitmq package)\n // TODO once we have proper drain handlers, we can remove this fixed wait\n this.logger.info('Waiting 2000ms to allow in-flight work to complete...');\n await setTimeout(2_000);\n\n await this.executeShutdownStage(SHUTDOWN_STAGES.DRAIN, shutdownTasksByStage[SHUTDOWN_STAGES.DRAIN]);\n await this.executeShutdownStage(SHUTDOWN_STAGES.CLOSE, shutdownTasksByStage[SHUTDOWN_STAGES.CLOSE]);\n\n await onShutdown?.();\n\n this.logger.info('Shutdown process completed');\n\n if (useExit0) {\n this.logger.info(`Exiting process after ${signal}`);\n process.exit(0);\n }\n } catch (error: any) {\n this.logger.error('Error during shutdown process, forcing process exit despite shutdown error', { error, signal });\n process.exit(1);\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"health-manager.cjs","names":["CLIENT_TYPES","CLIENT_DEFAULTS_MAP","client","error: any","ServiceUnavailableError","shutdownTasksByStage: Record<ShutdownStage, { fn: () => Promise<any>; name: string; }[]>","SHUTDOWN_STAGES"],"sources":["../../src/health-manager/health-manager.ts"],"sourcesContent":["import { setTimeout } from 'node:timers/promises';\nimport { ServiceUnavailableError } from '@autofleet/errors';\nimport type { LoggerInstanceManager } from '@autofleet/logger';\nimport { createHttpTerminator } from 'http-terminator';\nimport {\n type ClientConfig,\n type HealthManagerConfig,\n type HealthManagerOptions,\n type ClientType,\n type HealthCheckHandler,\n type ShutdownStage,\n type ServerConfig,\n CLIENT_TYPES,\n SHUTDOWN_STAGES,\n type ShutdownHandler,\n} from './types';\nimport { CLIENT_DEFAULTS_MAP } from './client-defaults';\n\n/**\n * Manages application health state and graceful shutdown for Kubernetes liveness/readiness probes\n *\n * Features:\n * - Provides aliveCheck() and readyCheck() methods for liveness/readiness probes\n * - Auto-registers SIGTERM/SIGINT handlers for graceful shutdown\n * - Manages ready state during shutdown to fail readiness probes\n */\nexport class HealthManager {\n private readonly DEFAULT_CONFIG: HealthManagerConfig = {\n shutdownDelayMs: 8_000,\n useExit0: true,\n shouldSetupSignalHandlers: true,\n enableLivenessOptimization: true,\n };\n\n private isShuttingDown = false;\n private isReady = false;\n\n private config: HealthManagerConfig;\n\n private clientsMap = new Map<string, ClientConfig<any>[]>();\n\n private livenessChecks: { check: HealthCheckHandler<any>; client: any; name: string; customHandlersPayload?: any; }[] = [];\n private readinessChecks: { check: HealthCheckHandler<any>; client: any; name: string; customHandlersPayload?: any; }[] = [];\n\n private logger: LoggerInstanceManager;\n\n /**\n * Creates a new HealthManager instance\n *\n * @param params Configuration options for health checks and shutdown behavior\n */\n constructor(params: HealthManagerOptions) {\n this.config = {\n ...this.DEFAULT_CONFIG,\n ...(params.config ?? {}),\n };\n\n this.logger = params.logger;\n\n this.storeClientsWithDefaults(params);\n\n this.initializeHealthChecks();\n\n if (this.config.shouldSetupSignalHandlers) {\n this.setupSignalHandlers();\n }\n }\n\n /**\n * Store clients with default health check and shutdown functions\n * @private\n */\n private storeClientsWithDefaults(params: HealthManagerOptions): void {\n const clients = params.clients;\n if (!clients) {\n return;\n }\n\n for (const [type, client] of Object.entries(clients)) {\n if (!client) {\n continue;\n }\n\n if (type === CLIENT_TYPES.SERVER) {\n this.attachServer(client);\n } else {\n const clientsArray = Array.isArray(client) ? client : [client];\n const defaults = CLIENT_DEFAULTS_MAP[type as ClientType] ?? CLIENT_DEFAULTS_MAP[CLIENT_TYPES.CUSTOM];\n\n const clientsWithDefaults = clientsArray.map(client => ({\n connection: client.connection,\n healthCheck: client.healthCheck ?? defaults?.healthCheck,\n shutdownHandlers: {\n ...defaults?.shutdownHandlers,\n ...client.shutdownHandlers,\n },\n options: {\n ...defaults?.options,\n ...client.options,\n name: client.options?.name || defaults?.options?.name || type,\n },\n }));\n\n this.clientsMap.set(type, clientsWithDefaults);\n }\n }\n }\n\n /**\n * Register SIGTERM and SIGINT signal listeners\n * @private\n */\n private setupSignalHandlers(): void {\n this.logger.info('Setting up global signal listeners for graceful shutdown');\n\n process.on('SIGTERM', async () => {\n await this.shutdown('SIGTERM');\n });\n\n process.on('SIGINT', async () => {\n await this.shutdown('SIGINT');\n });\n }\n\n /**\n * Check if liveness optimization is safe to enable for a given client configuration\n * If a client is in liveness but not readiness, we cannot skip liveness checks\n * because the optimization relies on readiness passing, but this client isn't checked in readiness\n * @private\n */\n private canSafelySkipLivenessWhenReady = (includeInLiveness: boolean | undefined, includeInReadiness: boolean | undefined): boolean => {\n // If not in liveness, optimization is safe (skipping liveness doesn't affect this client)\n if (!includeInLiveness) {\n return true;\n }\n\n // If in liveness, must also be in readiness for liveness optimization to be safe\n return !!includeInReadiness;\n };\n\n /**\n * Initialize health check arrays based on configured clients\n * @private\n */\n private initializeHealthChecks(): void {\n let allClientsAllowLivenessOptimization = true;\n\n this.clientsMap.forEach((clients) => {\n clients.forEach((client) => {\n if (!client.healthCheck) {\n return;\n }\n\n const includeInLiveness = client.options?.includeInLivenessCheck;\n const includeInReadiness = client.options?.includeInReadinessCheck;\n\n // Check if this client configuration allows liveness optimization\n if (!this.canSafelySkipLivenessWhenReady(includeInLiveness, includeInReadiness)) {\n allClientsAllowLivenessOptimization = false;\n }\n\n if (includeInLiveness) {\n this.livenessChecks.push({\n check: client.healthCheck,\n client: client.connection,\n name: client.options?.name || 'unknown',\n customHandlersPayload: client.options?.customHandlersPayload,\n });\n }\n\n if (includeInReadiness) {\n this.readinessChecks.push({\n check: client.healthCheck,\n client: client.connection,\n name: client.options?.name || 'unknown',\n customHandlersPayload: client.options?.customHandlersPayload,\n });\n }\n });\n });\n\n // Apply optimization setting: only enable if user requested it AND all clients allow it\n this.config.enableLivenessOptimization = this.config.enableLivenessOptimization && allClientsAllowLivenessOptimization;\n\n // Log optimization status\n if (this.config.enableLivenessOptimization) {\n this.logger.info('Liveness check optimization enabled - liveness checks will be skipped when pod is ready');\n } else if (!allClientsAllowLivenessOptimization) {\n this.logger.warn('Liveness check optimization disabled - some clients are in liveness checks but not in readiness checks');\n }\n }\n\n /**\n * Attach an HTTP or HTTPS server to be managed during shutdown\n * @param serverConfig Server configuration (ClientConfig with HTTP/HTTPS server)\n */\n attachServer(serverConfig: ServerConfig | ServerConfig[]): void {\n const serverDefaults = CLIENT_DEFAULTS_MAP[CLIENT_TYPES.SERVER];\n const serverConfigArray = Array.isArray(serverConfig) ? serverConfig : [serverConfig];\n\n const serverClients = serverConfigArray.map((config) => {\n // Create httpTerminator for this server instance\n const httpTerminator = createHttpTerminator({\n server: config.connection,\n });\n\n return {\n connection: config.connection,\n healthCheck: config.healthCheck ?? serverDefaults?.healthCheck,\n shutdownHandlers: {\n ...serverDefaults?.shutdownHandlers,\n ...config.shutdownHandlers,\n },\n options: {\n ...serverDefaults?.options,\n ...config.options,\n name: config.options?.name || serverDefaults?.options?.name || 'HTTP Server',\n customHandlersPayload: {\n ...config.options?.customHandlersPayload,\n httpTerminator,\n },\n },\n };\n });\n\n this.clientsMap.set(CLIENT_TYPES.SERVER, serverClients);\n }\n\n /**\n * Performs liveness health checks for clients configured with includeInLivenessCheck\n *\n * @returns Promise that resolves to { status: 'ok', statusCode: 200 } on success\n * @throws ServiceUnavailableError with statusCode 503 if any health check fails\n */\n async aliveCheck(): Promise<{ status: string; statusCode: number; }> {\n if (this.isShuttingDown) {\n return { statusCode: 200, status: 'ok' };\n }\n\n // Skip liveness check if optimization is enabled and the readiness check has already passed\n if (this.config.enableLivenessOptimization && this.isReady) {\n return { statusCode: 200, status: 'ok' };\n }\n\n try {\n await Promise.all(\n this.livenessChecks.map(({ check, client, name, customHandlersPayload }) =>\n check({ client, name, customHandlersPayload, logger: this.logger }),\n ),\n );\n\n return { statusCode: 200, status: 'ok' };\n } catch (error: any) {\n const err = new ServiceUnavailableError(`Liveness probe failed: ${error.message}`);\n err.stack = error.stack;\n throw err;\n }\n }\n\n /**\n * Performs readiness health checks for clients configured with includeInReadinessCheck\n *\n * @returns Promise that resolves to { status: 'ok', statusCode: 200 } if ready\n * @throws ServiceUnavailableError with statusCode 503 if not ready or health check fails\n */\n async readyCheck(): Promise<{ status: string; statusCode: number; }> {\n if (this.isShuttingDown) {\n this.isReady = false;\n this.logger.warn('Application is shutting down: readiness probe failed');\n throw new ServiceUnavailableError('Readiness probe failed: Application is shutting down');\n }\n\n try {\n await Promise.all(\n this.readinessChecks.map(({ check, client, name, customHandlersPayload }) =>\n check({ client, name, customHandlersPayload, logger: this.logger }),\n ),\n );\n this.isReady = true;\n\n return { statusCode: 200, status: 'ok' };\n } catch (error: any) {\n this.isReady = false;\n const err = new ServiceUnavailableError(`Readiness probe failed: ${error.message}`);\n err.stack = error.stack;\n throw err;\n }\n }\n\n /**\n * Groups client shutdown handlers by stage (stopAcceptingWork, drain, close).\n *\n * @private\n * @param signal - Signal name to pass to shutdown handlers\n * @returns Record of shutdown tasks organized by stage\n */\n private groupShutdownTasksByStage(signal: string): Record<ShutdownStage, { fn: () => Promise<any>; name: string; }[]> {\n const shutdownTasksByStage: Record<ShutdownStage, { fn: () => Promise<any>; name: string; }[]> = {\n [SHUTDOWN_STAGES.STOP_ACCEPTING_WORK]: [],\n [SHUTDOWN_STAGES.DRAIN]: [],\n [SHUTDOWN_STAGES.CLOSE]: [],\n };\n\n this.clientsMap.forEach((clients) => {\n clients.forEach((client) => {\n const clientName = client.options?.name || 'unknown';\n const enabledShutdownStages = client.options?.enabledShutdownStages;\n\n if (client.shutdownHandlers) {\n for (const [stage, shutdownHandler] of Object.entries(client.shutdownHandlers) as [ShutdownStage, ShutdownHandler<any>][]) {\n if (shutdownHandler && enabledShutdownStages?.includes(stage)) {\n shutdownTasksByStage[stage].push({\n fn: () => shutdownHandler({\n signal,\n client: client.connection,\n name: clientName,\n customHandlersPayload: client.options?.customHandlersPayload,\n logger: this.logger,\n }),\n name: clientName,\n });\n }\n }\n }\n });\n });\n\n return shutdownTasksByStage;\n }\n\n /**\n * Execute shutdown tasks for a specific stage\n * @private\n * @param stage - The shutdown stage to execute\n * @param tasks - Array of shutdown tasks to execute\n */\n private async executeShutdownStage(stage: ShutdownStage, tasks: { fn: () => Promise<any>; name: string; }[]): Promise<void> {\n if (tasks.length === 0) {\n return;\n }\n\n this.logger.info(`[${stage} stage] Start executing shutdown stage ${stage}...`);\n const results = await Promise.allSettled(tasks.map(t => t.fn()));\n results.forEach((result, index) => {\n if (result.status === 'rejected') {\n const { name } = tasks[index];\n this.logger.error(`[${stage} stage] Failed to shutdown '${name}'`, { error: result.reason });\n }\n });\n this.logger.info(`[${stage} stage] Shutdown stage ${stage} completed`);\n }\n\n /**\n * Triggers graceful shutdown process\n * Can be called manually or automatically via SIGTERM/SIGINT signal handlers\n *\n * Shutdown happens in three stages:\n * 1. stopAcceptingWork - Stop accepting new requests/work\n * 2. drain - Allow in-flight work to complete\n * 3. close - Close all connections and clean up resources\n *\n * @param signal - Signal name (e.g., 'SIGTERM', 'SIGINT', 'MANUAL')\n */\n async shutdown(signal = 'MANUAL'): Promise<void> {\n try {\n if (this.isShuttingDown) {\n this.logger.warn('Shutdown already in progress');\n return;\n }\n\n const { shutdownDelayMs, useExit0, onShutdown, beforeShutdown } = this.config;\n\n this.logger.info(`${signal} received: setting readiness state to false`);\n\n this.isShuttingDown = true;\n this.isReady = false;\n\n await beforeShutdown?.();\n\n this.logger.info(`Waiting ${shutdownDelayMs}ms before shutdown...`);\n await setTimeout(shutdownDelayMs);\n\n const shutdownTasksByStage = this.groupShutdownTasksByStage(signal);\n\n await this.executeShutdownStage(SHUTDOWN_STAGES.STOP_ACCEPTING_WORK, shutdownTasksByStage[SHUTDOWN_STAGES.STOP_ACCEPTING_WORK]);\n\n // Wait between stages to allow in-flight work to complete (we are missing a drain stage in our rabbitmq package)\n // TODO once we have proper drain handlers, we can remove this fixed wait\n this.logger.info('Waiting 2000ms to allow in-flight work to complete...');\n await setTimeout(2_000);\n\n await this.executeShutdownStage(SHUTDOWN_STAGES.DRAIN, shutdownTasksByStage[SHUTDOWN_STAGES.DRAIN]);\n await this.executeShutdownStage(SHUTDOWN_STAGES.CLOSE, shutdownTasksByStage[SHUTDOWN_STAGES.CLOSE]);\n\n await onShutdown?.();\n\n this.logger.info('Shutdown process completed');\n\n if (useExit0) {\n this.logger.info(`Exiting process after ${signal}`);\n process.exit(0);\n }\n } catch (error: any) {\n this.logger.error('Error during shutdown process, forcing process exit despite shutdown error', { error, signal });\n process.exit(1);\n }\n }\n}\n"],"mappings":"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"}
@@ -48,8 +48,8 @@ declare class HealthManager {
48
48
  */
49
49
  private initializeHealthChecks;
50
50
  /**
51
- * Attach an HTTP or HTTPS server (or multiple servers) to be managed during shutdown
52
- * @param serverConfig Server configuration (ClientConfig with HTTP/HTTPS server) - can be a single config or array of configs
51
+ * Attach an HTTP or HTTPS server to be managed during shutdown
52
+ * @param serverConfig Server configuration (ClientConfig with HTTP/HTTPS server)
53
53
  */
54
54
  attachServer(serverConfig: ServerConfig | ServerConfig[]): void;
55
55
  /**
@@ -74,7 +74,6 @@ declare class HealthManager {
74
74
  }>;
75
75
  /**
76
76
  * Groups client shutdown handlers by stage (stopAcceptingWork, drain, close).
77
- * Only includes handlers for stages each client has configured via shutdownStages.
78
77
  *
79
78
  * @private
80
79
  * @param signal - Signal name to pass to shutdown handlers
@@ -48,8 +48,8 @@ declare class HealthManager {
48
48
  */
49
49
  private initializeHealthChecks;
50
50
  /**
51
- * Attach an HTTP or HTTPS server (or multiple servers) to be managed during shutdown
52
- * @param serverConfig Server configuration (ClientConfig with HTTP/HTTPS server) - can be a single config or array of configs
51
+ * Attach an HTTP or HTTPS server to be managed during shutdown
52
+ * @param serverConfig Server configuration (ClientConfig with HTTP/HTTPS server)
53
53
  */
54
54
  attachServer(serverConfig: ServerConfig | ServerConfig[]): void;
55
55
  /**
@@ -74,7 +74,6 @@ declare class HealthManager {
74
74
  }>;
75
75
  /**
76
76
  * Groups client shutdown handlers by stage (stopAcceptingWork, drain, close).
77
- * Only includes handlers for stages each client has configured via shutdownStages.
78
77
  *
79
78
  * @private
80
79
  * @param signal - Signal name to pass to shutdown handlers
@@ -1,2 +1,2 @@
1
- import{CLIENT_TYPES as e,SHUTDOWN_STAGES as t}from"./types.js";import{CLIENT_DEFAULTS_MAP as n}from"./client-defaults.js";import{setTimeout as r}from"node:timers/promises";import{ServiceUnavailableError as i}from"@autofleet/errors";import{createHttpTerminator as a}from"http-terminator";var o=class{constructor(e){this.DEFAULT_CONFIG={shutdownDelayMs:8e3,useExit0:!0,shouldSetupSignalHandlers:!0,enableLivenessOptimization:!0},this.isShuttingDown=!1,this.isReady=!1,this.clientsMap=new Map,this.livenessChecks=[],this.readinessChecks=[],this.canSafelySkipLivenessWhenReady=(e,t)=>e?!!t:!0,this.config={...this.DEFAULT_CONFIG,...e.config??{}},this.logger=e.logger,this.storeClientsWithDefaults(e),this.initializeHealthChecks(),this.config.shouldSetupSignalHandlers&&this.setupSignalHandlers()}storeClientsWithDefaults(t){let r=t.clients;if(r){for(let[t,i]of Object.entries(r))if(i)if(t===e.SERVER)this.attachServer(i);else{let r=Array.isArray(i)?i:[i],a=n[t]??n[e.CUSTOM],o=r.map(e=>({connection:e.connection,healthCheck:e.healthCheck??a?.healthCheck,shutdownHandlers:{...a?.shutdownHandlers,...e.shutdownHandlers},options:{...a?.options,...e.options,name:e.options?.name||a?.options?.name||t}}));this.clientsMap.set(t,o)}}}setupSignalHandlers(){this.logger.info(`Setting up global signal listeners for graceful shutdown`),process.on(`SIGTERM`,async()=>{await this.shutdown(`SIGTERM`)}),process.on(`SIGINT`,async()=>{await this.shutdown(`SIGINT`)})}initializeHealthChecks(){let e=!0;this.clientsMap.forEach(t=>{t.forEach(t=>{if(!t.healthCheck)return;let n=t.options?.includeInLivenessCheck,r=t.options?.includeInReadinessCheck;this.canSafelySkipLivenessWhenReady(n,r)||(e=!1),n&&this.livenessChecks.push({check:t.healthCheck,client:t.connection,name:t.options?.name||`unknown`,customHandlersPayload:t.options?.customHandlersPayload}),r&&this.readinessChecks.push({check:t.healthCheck,client:t.connection,name:t.options?.name||`unknown`,customHandlersPayload:t.options?.customHandlersPayload})})}),this.config.enableLivenessOptimization=this.config.enableLivenessOptimization&&e,this.config.enableLivenessOptimization?this.logger.info(`Liveness check optimization enabled - liveness checks will be skipped when pod is ready`):e||this.logger.warn(`Liveness check optimization disabled - some clients are in liveness checks but not in readiness checks`)}attachServer(t){let r=n[e.SERVER],i=(Array.isArray(t)?t:[t]).map(e=>{let t=a({server:e.connection});return{connection:e.connection,healthCheck:e.healthCheck??r?.healthCheck,shutdownHandlers:{...r?.shutdownHandlers,...e.shutdownHandlers},options:{...r?.options,...e.options,name:e.options?.name||r?.options?.name||`HTTP Server`,customHandlersPayload:{...e.options?.customHandlersPayload,httpTerminator:t}}}});this.clientsMap.set(e.SERVER,i)}async aliveCheck(){if(this.isShuttingDown||this.config.enableLivenessOptimization&&this.isReady)return{statusCode:200,status:`ok`};try{return await Promise.all(this.livenessChecks.map(({check:e,client:t,name:n,customHandlersPayload:r})=>e({client:t,name:n,customHandlersPayload:r,logger:this.logger}))),{statusCode:200,status:`ok`}}catch(e){let t=new i(`Liveness probe failed: ${e.message}`);throw t.stack=e.stack,t}}async readyCheck(){if(this.isShuttingDown)throw this.isReady=!1,new i(`Readiness probe failed: Application is shutting down`);try{return await Promise.all(this.readinessChecks.map(({check:e,client:t,name:n,customHandlersPayload:r})=>e({client:t,name:n,customHandlersPayload:r,logger:this.logger}))),this.isReady=!0,{statusCode:200,status:`ok`}}catch(e){this.isReady=!1;let t=new i(`Readiness probe failed: ${e.message}`);throw t.stack=e.stack,t}}groupShutdownTasksByStage(e){let n={[t.STOP_ACCEPTING_WORK]:[],[t.DRAIN]:[],[t.CLOSE]:[]};return this.clientsMap.forEach(t=>{t.forEach(t=>{let r=t.options?.name||`unknown`,i=t.options?.shutdownStages;if(t.shutdownHandlers)for(let[a,o]of Object.entries(t.shutdownHandlers))o&&i?.includes(a)&&n[a].push({fn:()=>o({signal:e,client:t.connection,name:r,customHandlersPayload:t.options?.customHandlersPayload,logger:this.logger}),name:r})})}),n}async executeShutdownStage(e,t){t.length!==0&&(this.logger.info(`[${e} stage] Start executing shutdown...`),(await Promise.allSettled(t.map(e=>e.fn()))).forEach((n,r)=>{if(n.status===`rejected`){let{name:i}=t[r];this.logger.error(`[${e} stage] Failed to shutdown '${i}'`,{error:n.reason})}}),this.logger.info(`[${e} stage] Shutdown completed`))}async shutdown(e=`MANUAL`){try{if(this.isShuttingDown){this.logger.warn(`Shutdown already in progress`);return}let{shutdownDelayMs:n,useExit0:i,onShutdown:a,beforeShutdown:o}=this.config;this.logger.info(`${e} received: setting readiness state to false`),this.isShuttingDown=!0,this.isReady=!1,await o?.(),this.logger.info(`Waiting ${n}ms before shutdown...`),await r(n);let s=this.groupShutdownTasksByStage(e);await this.executeShutdownStage(t.STOP_ACCEPTING_WORK,s[t.STOP_ACCEPTING_WORK]),this.logger.info(`Waiting 2000ms to allow in-flight work to complete...`),await r(2e3),await this.executeShutdownStage(t.DRAIN,s[t.DRAIN]),await this.executeShutdownStage(t.CLOSE,s[t.CLOSE]),await a?.(),this.logger.info(`Shutdown process completed`),i&&(this.logger.info(`Exiting process after ${e}`),process.exit(0))}catch(t){this.logger.error(`Error during shutdown process, forcing process exit despite shutdown error`,{error:t,signal:e}),process.exit(1)}}};export{o as HealthManager};
1
+ import{CLIENT_TYPES as e,SHUTDOWN_STAGES as t}from"./types.js";import{CLIENT_DEFAULTS_MAP as n}from"./client-defaults.js";import{setTimeout as r}from"node:timers/promises";import{ServiceUnavailableError as i}from"@autofleet/errors";import{createHttpTerminator as a}from"http-terminator";var o=class{constructor(e){this.DEFAULT_CONFIG={shutdownDelayMs:8e3,useExit0:!0,shouldSetupSignalHandlers:!0,enableLivenessOptimization:!0},this.isShuttingDown=!1,this.isReady=!1,this.clientsMap=new Map,this.livenessChecks=[],this.readinessChecks=[],this.canSafelySkipLivenessWhenReady=(e,t)=>e?!!t:!0,this.config={...this.DEFAULT_CONFIG,...e.config??{}},this.logger=e.logger,this.storeClientsWithDefaults(e),this.initializeHealthChecks(),this.config.shouldSetupSignalHandlers&&this.setupSignalHandlers()}storeClientsWithDefaults(t){let r=t.clients;if(r){for(let[t,i]of Object.entries(r))if(i)if(t===e.SERVER)this.attachServer(i);else{let r=Array.isArray(i)?i:[i],a=n[t]??n[e.CUSTOM],o=r.map(e=>({connection:e.connection,healthCheck:e.healthCheck??a?.healthCheck,shutdownHandlers:{...a?.shutdownHandlers,...e.shutdownHandlers},options:{...a?.options,...e.options,name:e.options?.name||a?.options?.name||t}}));this.clientsMap.set(t,o)}}}setupSignalHandlers(){this.logger.info(`Setting up global signal listeners for graceful shutdown`),process.on(`SIGTERM`,async()=>{await this.shutdown(`SIGTERM`)}),process.on(`SIGINT`,async()=>{await this.shutdown(`SIGINT`)})}initializeHealthChecks(){let e=!0;this.clientsMap.forEach(t=>{t.forEach(t=>{if(!t.healthCheck)return;let n=t.options?.includeInLivenessCheck,r=t.options?.includeInReadinessCheck;this.canSafelySkipLivenessWhenReady(n,r)||(e=!1),n&&this.livenessChecks.push({check:t.healthCheck,client:t.connection,name:t.options?.name||`unknown`,customHandlersPayload:t.options?.customHandlersPayload}),r&&this.readinessChecks.push({check:t.healthCheck,client:t.connection,name:t.options?.name||`unknown`,customHandlersPayload:t.options?.customHandlersPayload})})}),this.config.enableLivenessOptimization=this.config.enableLivenessOptimization&&e,this.config.enableLivenessOptimization?this.logger.info(`Liveness check optimization enabled - liveness checks will be skipped when pod is ready`):e||this.logger.warn(`Liveness check optimization disabled - some clients are in liveness checks but not in readiness checks`)}attachServer(t){let r=n[e.SERVER],i=(Array.isArray(t)?t:[t]).map(e=>{let t=a({server:e.connection});return{connection:e.connection,healthCheck:e.healthCheck??r?.healthCheck,shutdownHandlers:{...r?.shutdownHandlers,...e.shutdownHandlers},options:{...r?.options,...e.options,name:e.options?.name||r?.options?.name||`HTTP Server`,customHandlersPayload:{...e.options?.customHandlersPayload,httpTerminator:t}}}});this.clientsMap.set(e.SERVER,i)}async aliveCheck(){if(this.isShuttingDown||this.config.enableLivenessOptimization&&this.isReady)return{statusCode:200,status:`ok`};try{return await Promise.all(this.livenessChecks.map(({check:e,client:t,name:n,customHandlersPayload:r})=>e({client:t,name:n,customHandlersPayload:r,logger:this.logger}))),{statusCode:200,status:`ok`}}catch(e){let t=new i(`Liveness probe failed: ${e.message}`);throw t.stack=e.stack,t}}async readyCheck(){if(this.isShuttingDown)throw this.isReady=!1,this.logger.warn(`Application is shutting down: readiness probe failed`),new i(`Readiness probe failed: Application is shutting down`);try{return await Promise.all(this.readinessChecks.map(({check:e,client:t,name:n,customHandlersPayload:r})=>e({client:t,name:n,customHandlersPayload:r,logger:this.logger}))),this.isReady=!0,{statusCode:200,status:`ok`}}catch(e){this.isReady=!1;let t=new i(`Readiness probe failed: ${e.message}`);throw t.stack=e.stack,t}}groupShutdownTasksByStage(e){let n={[t.STOP_ACCEPTING_WORK]:[],[t.DRAIN]:[],[t.CLOSE]:[]};return this.clientsMap.forEach(t=>{t.forEach(t=>{let r=t.options?.name||`unknown`,i=t.options?.enabledShutdownStages;if(t.shutdownHandlers)for(let[a,o]of Object.entries(t.shutdownHandlers))o&&i?.includes(a)&&n[a].push({fn:()=>o({signal:e,client:t.connection,name:r,customHandlersPayload:t.options?.customHandlersPayload,logger:this.logger}),name:r})})}),n}async executeShutdownStage(e,t){t.length!==0&&(this.logger.info(`[${e} stage] Start executing shutdown stage ${e}...`),(await Promise.allSettled(t.map(e=>e.fn()))).forEach((n,r)=>{if(n.status===`rejected`){let{name:i}=t[r];this.logger.error(`[${e} stage] Failed to shutdown '${i}'`,{error:n.reason})}}),this.logger.info(`[${e} stage] Shutdown stage ${e} completed`))}async shutdown(e=`MANUAL`){try{if(this.isShuttingDown){this.logger.warn(`Shutdown already in progress`);return}let{shutdownDelayMs:n,useExit0:i,onShutdown:a,beforeShutdown:o}=this.config;this.logger.info(`${e} received: setting readiness state to false`),this.isShuttingDown=!0,this.isReady=!1,await o?.(),this.logger.info(`Waiting ${n}ms before shutdown...`),await r(n);let s=this.groupShutdownTasksByStage(e);await this.executeShutdownStage(t.STOP_ACCEPTING_WORK,s[t.STOP_ACCEPTING_WORK]),this.logger.info(`Waiting 2000ms to allow in-flight work to complete...`),await r(2e3),await this.executeShutdownStage(t.DRAIN,s[t.DRAIN]),await this.executeShutdownStage(t.CLOSE,s[t.CLOSE]),await a?.(),this.logger.info(`Shutdown process completed`),i&&(this.logger.info(`Exiting process after ${e}`),process.exit(0))}catch(t){this.logger.error(`Error during shutdown process, forcing process exit despite shutdown error`,{error:t,signal:e}),process.exit(1)}}};export{o as HealthManager};
2
2
  //# sourceMappingURL=health-manager.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"health-manager.js","names":["client","error: any","shutdownTasksByStage: Record<ShutdownStage, { fn: () => Promise<any>; name: string; }[]>"],"sources":["../../src/health-manager/health-manager.ts"],"sourcesContent":["import { setTimeout } from 'node:timers/promises';\nimport { ServiceUnavailableError } from '@autofleet/errors';\nimport type { LoggerInstanceManager } from '@autofleet/logger';\nimport { createHttpTerminator } from 'http-terminator';\nimport {\n type ClientConfig,\n type HealthManagerConfig,\n type HealthManagerOptions,\n type ClientType,\n type HealthCheckHandler,\n type ShutdownStage,\n type ServerConfig,\n CLIENT_TYPES,\n SHUTDOWN_STAGES,\n type ShutdownHandler,\n} from './types';\nimport { CLIENT_DEFAULTS_MAP } from './client-defaults';\n\n/**\n * Manages application health state and graceful shutdown for Kubernetes liveness/readiness probes\n *\n * Features:\n * - Provides aliveCheck() and readyCheck() methods for liveness/readiness probes\n * - Auto-registers SIGTERM/SIGINT handlers for graceful shutdown\n * - Manages ready state during shutdown to fail readiness probes\n */\nexport class HealthManager {\n private readonly DEFAULT_CONFIG: HealthManagerConfig = {\n shutdownDelayMs: 8_000,\n useExit0: true,\n shouldSetupSignalHandlers: true,\n enableLivenessOptimization: true,\n };\n\n private isShuttingDown = false;\n private isReady = false;\n\n private config: HealthManagerConfig;\n\n private clientsMap = new Map<string, ClientConfig<any>[]>();\n\n private livenessChecks: { check: HealthCheckHandler; client: any; name: string; customHandlersPayload?: any; }[] = [];\n private readinessChecks: { check: HealthCheckHandler; client: any; name: string; customHandlersPayload?: any; }[] = [];\n\n private logger: LoggerInstanceManager;\n\n /**\n * Creates a new HealthManager instance\n *\n * @param params Configuration options for health checks and shutdown behavior\n */\n constructor(params: HealthManagerOptions) {\n this.config = {\n ...this.DEFAULT_CONFIG,\n ...(params.config ?? {}),\n };\n\n this.logger = params.logger;\n\n this.storeClientsWithDefaults(params);\n\n this.initializeHealthChecks();\n\n if (this.config.shouldSetupSignalHandlers) {\n this.setupSignalHandlers();\n }\n }\n\n /**\n * Store clients with default health check and shutdown functions\n * @private\n */\n private storeClientsWithDefaults(params: HealthManagerOptions): void {\n const clients = params.clients;\n if (!clients) {\n return;\n }\n\n for (const [type, client] of Object.entries(clients)) {\n if (!client) {\n continue;\n }\n\n if (type === CLIENT_TYPES.SERVER) {\n this.attachServer(client);\n } else {\n const clientsArray = Array.isArray(client) ? client : [client];\n const defaults = CLIENT_DEFAULTS_MAP[type as ClientType] ?? CLIENT_DEFAULTS_MAP[CLIENT_TYPES.CUSTOM];\n\n const clientsWithDefaults = clientsArray.map(client => ({\n connection: client.connection,\n healthCheck: client.healthCheck ?? defaults?.healthCheck,\n shutdownHandlers: {\n ...defaults?.shutdownHandlers,\n ...client.shutdownHandlers,\n },\n options: {\n ...defaults?.options,\n ...client.options,\n name: client.options?.name || defaults?.options?.name || type,\n },\n }));\n\n this.clientsMap.set(type, clientsWithDefaults);\n }\n }\n }\n\n /**\n * Register SIGTERM and SIGINT signal listeners\n * @private\n */\n private setupSignalHandlers(): void {\n this.logger.info('Setting up global signal listeners for graceful shutdown');\n\n process.on('SIGTERM', async () => {\n await this.shutdown('SIGTERM');\n });\n\n process.on('SIGINT', async () => {\n await this.shutdown('SIGINT');\n });\n }\n\n /**\n * Check if liveness optimization is safe to enable for a given client configuration\n * If a client is in liveness but not readiness, we cannot skip liveness checks\n * because the optimization relies on readiness passing, but this client isn't checked in readiness\n * @private\n */\n private canSafelySkipLivenessWhenReady = (includeInLiveness: boolean | undefined, includeInReadiness: boolean | undefined): boolean => {\n // If not in liveness, optimization is safe (not affected)\n if (!includeInLiveness) {\n return true;\n }\n\n // If in liveness, must also be in readiness for optimization to be safe\n return !!includeInReadiness;\n };\n\n /**\n * Initialize health check arrays based on configured clients\n * @private\n */\n private initializeHealthChecks(): void {\n let allClientsAllowLivenessOptimization = true;\n\n this.clientsMap.forEach((clients) => {\n clients.forEach((client) => {\n if (!client.healthCheck) {\n return;\n }\n\n const includeInLiveness = client.options?.includeInLivenessCheck;\n const includeInReadiness = client.options?.includeInReadinessCheck;\n\n // Check if this client configuration allows liveness optimization\n if (!this.canSafelySkipLivenessWhenReady(includeInLiveness, includeInReadiness)) {\n allClientsAllowLivenessOptimization = false;\n }\n\n if (includeInLiveness) {\n this.livenessChecks.push({\n check: client.healthCheck,\n client: client.connection,\n name: client.options?.name || 'unknown',\n customHandlersPayload: client.options?.customHandlersPayload,\n });\n }\n\n if (includeInReadiness) {\n this.readinessChecks.push({\n check: client.healthCheck,\n client: client.connection,\n name: client.options?.name || 'unknown',\n customHandlersPayload: client.options?.customHandlersPayload,\n });\n }\n });\n });\n\n // Apply optimization setting: only enable if user requested it AND all clients allow it\n this.config.enableLivenessOptimization = this.config.enableLivenessOptimization && allClientsAllowLivenessOptimization;\n\n // Log optimization status\n if (this.config.enableLivenessOptimization) {\n this.logger.info('Liveness check optimization enabled - liveness checks will be skipped when pod is ready');\n } else if (!allClientsAllowLivenessOptimization) {\n this.logger.warn('Liveness check optimization disabled - some clients are in liveness checks but not in readiness checks');\n }\n }\n\n /**\n * Attach an HTTP or HTTPS server (or multiple servers) to be managed during shutdown\n * @param serverConfig Server configuration (ClientConfig with HTTP/HTTPS server) - can be a single config or array of configs\n */\n attachServer(serverConfig: ServerConfig | ServerConfig[]): void {\n const serverDefaults = CLIENT_DEFAULTS_MAP[CLIENT_TYPES.SERVER];\n const serverConfigArray = Array.isArray(serverConfig) ? serverConfig : [serverConfig];\n\n const serverClients = serverConfigArray.map((config) => {\n // Create httpTerminator for this server instance\n const httpTerminator = createHttpTerminator({\n server: config.connection,\n });\n\n return {\n connection: config.connection,\n healthCheck: config.healthCheck ?? serverDefaults?.healthCheck,\n shutdownHandlers: {\n ...serverDefaults?.shutdownHandlers,\n ...config.shutdownHandlers,\n },\n options: {\n ...serverDefaults?.options,\n ...config.options,\n name: config.options?.name || serverDefaults?.options?.name || 'HTTP Server',\n customHandlersPayload: {\n ...config.options?.customHandlersPayload,\n httpTerminator,\n },\n },\n };\n });\n\n this.clientsMap.set(CLIENT_TYPES.SERVER, serverClients);\n }\n\n /**\n * Performs liveness health checks for clients configured with includeInLivenessCheck\n *\n * @returns Promise that resolves to { status: 'ok', statusCode: 200 } on success\n * @throws ServiceUnavailableError with statusCode 503 if any health check fails\n */\n async aliveCheck(): Promise<{ status: string; statusCode: number; }> {\n if (this.isShuttingDown) {\n return { statusCode: 200, status: 'ok' };\n }\n\n // Skip liveness check if optimization is enabled and the readiness check has already passed\n if (this.config.enableLivenessOptimization && this.isReady) {\n return { statusCode: 200, status: 'ok' };\n }\n\n try {\n await Promise.all(\n this.livenessChecks.map(({ check, client, name, customHandlersPayload }) =>\n check({ client, name, customHandlersPayload, logger: this.logger }),\n ),\n );\n\n return { statusCode: 200, status: 'ok' };\n } catch (error: any) {\n const err = new ServiceUnavailableError(`Liveness probe failed: ${error.message}`);\n err.stack = error.stack;\n throw err;\n }\n }\n\n /**\n * Performs readiness health checks for clients configured with includeInReadinessCheck\n *\n * @returns Promise that resolves to { status: 'ok', statusCode: 200 } if ready\n * @throws ServiceUnavailableError with statusCode 503 if not ready or health check fails\n */\n async readyCheck(): Promise<{ status: string; statusCode: number; }> {\n if (this.isShuttingDown) {\n this.isReady = false;\n throw new ServiceUnavailableError('Readiness probe failed: Application is shutting down');\n }\n\n try {\n await Promise.all(\n this.readinessChecks.map(({ check, client, name, customHandlersPayload }) =>\n check({ client, name, customHandlersPayload, logger: this.logger }),\n ),\n );\n this.isReady = true;\n\n return { statusCode: 200, status: 'ok' };\n } catch (error: any) {\n this.isReady = false;\n const err = new ServiceUnavailableError(`Readiness probe failed: ${error.message}`);\n err.stack = error.stack;\n throw err;\n }\n }\n\n /**\n * Groups client shutdown handlers by stage (stopAcceptingWork, drain, close).\n * Only includes handlers for stages each client has configured via shutdownStages.\n *\n * @private\n * @param signal - Signal name to pass to shutdown handlers\n * @returns Record of shutdown tasks organized by stage\n */\n private groupShutdownTasksByStage(signal: string): Record<ShutdownStage, { fn: () => Promise<any>; name: string; }[]> {\n const shutdownTasksByStage: Record<ShutdownStage, { fn: () => Promise<any>; name: string; }[]> = {\n [SHUTDOWN_STAGES.STOP_ACCEPTING_WORK]: [],\n [SHUTDOWN_STAGES.DRAIN]: [],\n [SHUTDOWN_STAGES.CLOSE]: [],\n };\n\n this.clientsMap.forEach((clients) => {\n clients.forEach((client) => {\n const clientName = client.options?.name || 'unknown';\n const configuredShutdownStages = client.options?.shutdownStages;\n\n if (client.shutdownHandlers) {\n for (const [stage, shutdownHandler] of Object.entries(client.shutdownHandlers) as [ShutdownStage, ShutdownHandler][]) {\n if (shutdownHandler && configuredShutdownStages?.includes(stage)) {\n shutdownTasksByStage[stage].push({\n fn: () => shutdownHandler({\n signal,\n client: client.connection,\n name: clientName,\n customHandlersPayload: client.options?.customHandlersPayload,\n logger: this.logger,\n }),\n name: clientName,\n });\n }\n }\n }\n });\n });\n\n return shutdownTasksByStage;\n }\n\n /**\n * Execute shutdown tasks for a specific stage\n * @private\n * @param stage - The shutdown stage to execute\n * @param tasks - Array of shutdown tasks to execute\n */\n private async executeShutdownStage(stage: ShutdownStage, tasks: { fn: () => Promise<any>; name: string; }[]): Promise<void> {\n if (tasks.length === 0) {\n return;\n }\n\n this.logger.info(`[${stage} stage] Start executing shutdown...`);\n const results = await Promise.allSettled(tasks.map(t => t.fn()));\n results.forEach((result, index) => {\n if (result.status === 'rejected') {\n const { name } = tasks[index];\n this.logger.error(`[${stage} stage] Failed to shutdown '${name}'`, { error: result.reason });\n }\n });\n this.logger.info(`[${stage} stage] Shutdown completed`);\n }\n\n /**\n * Triggers graceful shutdown process\n * Can be called manually or automatically via SIGTERM/SIGINT signal handlers\n *\n * Shutdown happens in three stages:\n * 1. stopAcceptingWork - Stop accepting new requests/work\n * 2. drain - Allow in-flight work to complete\n * 3. close - Close all connections and clean up resources\n *\n * @param signal - Signal name (e.g., 'SIGTERM', 'SIGINT', 'MANUAL')\n */\n async shutdown(signal = 'MANUAL'): Promise<void> {\n try {\n if (this.isShuttingDown) {\n this.logger.warn('Shutdown already in progress');\n return;\n }\n\n const { shutdownDelayMs, useExit0, onShutdown, beforeShutdown } = this.config;\n\n this.logger.info(`${signal} received: setting readiness state to false`);\n\n this.isShuttingDown = true;\n this.isReady = false;\n\n await beforeShutdown?.();\n\n this.logger.info(`Waiting ${shutdownDelayMs}ms before shutdown...`);\n await setTimeout(shutdownDelayMs);\n\n const shutdownTasksByStage = this.groupShutdownTasksByStage(signal);\n\n await this.executeShutdownStage(SHUTDOWN_STAGES.STOP_ACCEPTING_WORK, shutdownTasksByStage[SHUTDOWN_STAGES.STOP_ACCEPTING_WORK]);\n\n // Wait between stages to allow in-flight work to complete (we are missing a drain stage in our rabbitmq package)\n // TODO once we have proper drain handlers, we can remove this fixed wait\n this.logger.info('Waiting 2000ms to allow in-flight work to complete...');\n await setTimeout(2_000);\n\n await this.executeShutdownStage(SHUTDOWN_STAGES.DRAIN, shutdownTasksByStage[SHUTDOWN_STAGES.DRAIN]);\n await this.executeShutdownStage(SHUTDOWN_STAGES.CLOSE, shutdownTasksByStage[SHUTDOWN_STAGES.CLOSE]);\n\n await onShutdown?.();\n\n this.logger.info('Shutdown process completed');\n\n if (useExit0) {\n this.logger.info(`Exiting process after ${signal}`);\n process.exit(0);\n }\n } catch (error: any) {\n this.logger.error('Error during shutdown process, forcing process exit despite shutdown error', { error, signal });\n process.exit(1);\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"health-manager.js","names":["client","error: any","shutdownTasksByStage: Record<ShutdownStage, { fn: () => Promise<any>; name: string; }[]>"],"sources":["../../src/health-manager/health-manager.ts"],"sourcesContent":["import { setTimeout } from 'node:timers/promises';\nimport { ServiceUnavailableError } from '@autofleet/errors';\nimport type { LoggerInstanceManager } from '@autofleet/logger';\nimport { createHttpTerminator } from 'http-terminator';\nimport {\n type ClientConfig,\n type HealthManagerConfig,\n type HealthManagerOptions,\n type ClientType,\n type HealthCheckHandler,\n type ShutdownStage,\n type ServerConfig,\n CLIENT_TYPES,\n SHUTDOWN_STAGES,\n type ShutdownHandler,\n} from './types';\nimport { CLIENT_DEFAULTS_MAP } from './client-defaults';\n\n/**\n * Manages application health state and graceful shutdown for Kubernetes liveness/readiness probes\n *\n * Features:\n * - Provides aliveCheck() and readyCheck() methods for liveness/readiness probes\n * - Auto-registers SIGTERM/SIGINT handlers for graceful shutdown\n * - Manages ready state during shutdown to fail readiness probes\n */\nexport class HealthManager {\n private readonly DEFAULT_CONFIG: HealthManagerConfig = {\n shutdownDelayMs: 8_000,\n useExit0: true,\n shouldSetupSignalHandlers: true,\n enableLivenessOptimization: true,\n };\n\n private isShuttingDown = false;\n private isReady = false;\n\n private config: HealthManagerConfig;\n\n private clientsMap = new Map<string, ClientConfig<any>[]>();\n\n private livenessChecks: { check: HealthCheckHandler<any>; client: any; name: string; customHandlersPayload?: any; }[] = [];\n private readinessChecks: { check: HealthCheckHandler<any>; client: any; name: string; customHandlersPayload?: any; }[] = [];\n\n private logger: LoggerInstanceManager;\n\n /**\n * Creates a new HealthManager instance\n *\n * @param params Configuration options for health checks and shutdown behavior\n */\n constructor(params: HealthManagerOptions) {\n this.config = {\n ...this.DEFAULT_CONFIG,\n ...(params.config ?? {}),\n };\n\n this.logger = params.logger;\n\n this.storeClientsWithDefaults(params);\n\n this.initializeHealthChecks();\n\n if (this.config.shouldSetupSignalHandlers) {\n this.setupSignalHandlers();\n }\n }\n\n /**\n * Store clients with default health check and shutdown functions\n * @private\n */\n private storeClientsWithDefaults(params: HealthManagerOptions): void {\n const clients = params.clients;\n if (!clients) {\n return;\n }\n\n for (const [type, client] of Object.entries(clients)) {\n if (!client) {\n continue;\n }\n\n if (type === CLIENT_TYPES.SERVER) {\n this.attachServer(client);\n } else {\n const clientsArray = Array.isArray(client) ? client : [client];\n const defaults = CLIENT_DEFAULTS_MAP[type as ClientType] ?? CLIENT_DEFAULTS_MAP[CLIENT_TYPES.CUSTOM];\n\n const clientsWithDefaults = clientsArray.map(client => ({\n connection: client.connection,\n healthCheck: client.healthCheck ?? defaults?.healthCheck,\n shutdownHandlers: {\n ...defaults?.shutdownHandlers,\n ...client.shutdownHandlers,\n },\n options: {\n ...defaults?.options,\n ...client.options,\n name: client.options?.name || defaults?.options?.name || type,\n },\n }));\n\n this.clientsMap.set(type, clientsWithDefaults);\n }\n }\n }\n\n /**\n * Register SIGTERM and SIGINT signal listeners\n * @private\n */\n private setupSignalHandlers(): void {\n this.logger.info('Setting up global signal listeners for graceful shutdown');\n\n process.on('SIGTERM', async () => {\n await this.shutdown('SIGTERM');\n });\n\n process.on('SIGINT', async () => {\n await this.shutdown('SIGINT');\n });\n }\n\n /**\n * Check if liveness optimization is safe to enable for a given client configuration\n * If a client is in liveness but not readiness, we cannot skip liveness checks\n * because the optimization relies on readiness passing, but this client isn't checked in readiness\n * @private\n */\n private canSafelySkipLivenessWhenReady = (includeInLiveness: boolean | undefined, includeInReadiness: boolean | undefined): boolean => {\n // If not in liveness, optimization is safe (skipping liveness doesn't affect this client)\n if (!includeInLiveness) {\n return true;\n }\n\n // If in liveness, must also be in readiness for liveness optimization to be safe\n return !!includeInReadiness;\n };\n\n /**\n * Initialize health check arrays based on configured clients\n * @private\n */\n private initializeHealthChecks(): void {\n let allClientsAllowLivenessOptimization = true;\n\n this.clientsMap.forEach((clients) => {\n clients.forEach((client) => {\n if (!client.healthCheck) {\n return;\n }\n\n const includeInLiveness = client.options?.includeInLivenessCheck;\n const includeInReadiness = client.options?.includeInReadinessCheck;\n\n // Check if this client configuration allows liveness optimization\n if (!this.canSafelySkipLivenessWhenReady(includeInLiveness, includeInReadiness)) {\n allClientsAllowLivenessOptimization = false;\n }\n\n if (includeInLiveness) {\n this.livenessChecks.push({\n check: client.healthCheck,\n client: client.connection,\n name: client.options?.name || 'unknown',\n customHandlersPayload: client.options?.customHandlersPayload,\n });\n }\n\n if (includeInReadiness) {\n this.readinessChecks.push({\n check: client.healthCheck,\n client: client.connection,\n name: client.options?.name || 'unknown',\n customHandlersPayload: client.options?.customHandlersPayload,\n });\n }\n });\n });\n\n // Apply optimization setting: only enable if user requested it AND all clients allow it\n this.config.enableLivenessOptimization = this.config.enableLivenessOptimization && allClientsAllowLivenessOptimization;\n\n // Log optimization status\n if (this.config.enableLivenessOptimization) {\n this.logger.info('Liveness check optimization enabled - liveness checks will be skipped when pod is ready');\n } else if (!allClientsAllowLivenessOptimization) {\n this.logger.warn('Liveness check optimization disabled - some clients are in liveness checks but not in readiness checks');\n }\n }\n\n /**\n * Attach an HTTP or HTTPS server to be managed during shutdown\n * @param serverConfig Server configuration (ClientConfig with HTTP/HTTPS server)\n */\n attachServer(serverConfig: ServerConfig | ServerConfig[]): void {\n const serverDefaults = CLIENT_DEFAULTS_MAP[CLIENT_TYPES.SERVER];\n const serverConfigArray = Array.isArray(serverConfig) ? serverConfig : [serverConfig];\n\n const serverClients = serverConfigArray.map((config) => {\n // Create httpTerminator for this server instance\n const httpTerminator = createHttpTerminator({\n server: config.connection,\n });\n\n return {\n connection: config.connection,\n healthCheck: config.healthCheck ?? serverDefaults?.healthCheck,\n shutdownHandlers: {\n ...serverDefaults?.shutdownHandlers,\n ...config.shutdownHandlers,\n },\n options: {\n ...serverDefaults?.options,\n ...config.options,\n name: config.options?.name || serverDefaults?.options?.name || 'HTTP Server',\n customHandlersPayload: {\n ...config.options?.customHandlersPayload,\n httpTerminator,\n },\n },\n };\n });\n\n this.clientsMap.set(CLIENT_TYPES.SERVER, serverClients);\n }\n\n /**\n * Performs liveness health checks for clients configured with includeInLivenessCheck\n *\n * @returns Promise that resolves to { status: 'ok', statusCode: 200 } on success\n * @throws ServiceUnavailableError with statusCode 503 if any health check fails\n */\n async aliveCheck(): Promise<{ status: string; statusCode: number; }> {\n if (this.isShuttingDown) {\n return { statusCode: 200, status: 'ok' };\n }\n\n // Skip liveness check if optimization is enabled and the readiness check has already passed\n if (this.config.enableLivenessOptimization && this.isReady) {\n return { statusCode: 200, status: 'ok' };\n }\n\n try {\n await Promise.all(\n this.livenessChecks.map(({ check, client, name, customHandlersPayload }) =>\n check({ client, name, customHandlersPayload, logger: this.logger }),\n ),\n );\n\n return { statusCode: 200, status: 'ok' };\n } catch (error: any) {\n const err = new ServiceUnavailableError(`Liveness probe failed: ${error.message}`);\n err.stack = error.stack;\n throw err;\n }\n }\n\n /**\n * Performs readiness health checks for clients configured with includeInReadinessCheck\n *\n * @returns Promise that resolves to { status: 'ok', statusCode: 200 } if ready\n * @throws ServiceUnavailableError with statusCode 503 if not ready or health check fails\n */\n async readyCheck(): Promise<{ status: string; statusCode: number; }> {\n if (this.isShuttingDown) {\n this.isReady = false;\n this.logger.warn('Application is shutting down: readiness probe failed');\n throw new ServiceUnavailableError('Readiness probe failed: Application is shutting down');\n }\n\n try {\n await Promise.all(\n this.readinessChecks.map(({ check, client, name, customHandlersPayload }) =>\n check({ client, name, customHandlersPayload, logger: this.logger }),\n ),\n );\n this.isReady = true;\n\n return { statusCode: 200, status: 'ok' };\n } catch (error: any) {\n this.isReady = false;\n const err = new ServiceUnavailableError(`Readiness probe failed: ${error.message}`);\n err.stack = error.stack;\n throw err;\n }\n }\n\n /**\n * Groups client shutdown handlers by stage (stopAcceptingWork, drain, close).\n *\n * @private\n * @param signal - Signal name to pass to shutdown handlers\n * @returns Record of shutdown tasks organized by stage\n */\n private groupShutdownTasksByStage(signal: string): Record<ShutdownStage, { fn: () => Promise<any>; name: string; }[]> {\n const shutdownTasksByStage: Record<ShutdownStage, { fn: () => Promise<any>; name: string; }[]> = {\n [SHUTDOWN_STAGES.STOP_ACCEPTING_WORK]: [],\n [SHUTDOWN_STAGES.DRAIN]: [],\n [SHUTDOWN_STAGES.CLOSE]: [],\n };\n\n this.clientsMap.forEach((clients) => {\n clients.forEach((client) => {\n const clientName = client.options?.name || 'unknown';\n const enabledShutdownStages = client.options?.enabledShutdownStages;\n\n if (client.shutdownHandlers) {\n for (const [stage, shutdownHandler] of Object.entries(client.shutdownHandlers) as [ShutdownStage, ShutdownHandler<any>][]) {\n if (shutdownHandler && enabledShutdownStages?.includes(stage)) {\n shutdownTasksByStage[stage].push({\n fn: () => shutdownHandler({\n signal,\n client: client.connection,\n name: clientName,\n customHandlersPayload: client.options?.customHandlersPayload,\n logger: this.logger,\n }),\n name: clientName,\n });\n }\n }\n }\n });\n });\n\n return shutdownTasksByStage;\n }\n\n /**\n * Execute shutdown tasks for a specific stage\n * @private\n * @param stage - The shutdown stage to execute\n * @param tasks - Array of shutdown tasks to execute\n */\n private async executeShutdownStage(stage: ShutdownStage, tasks: { fn: () => Promise<any>; name: string; }[]): Promise<void> {\n if (tasks.length === 0) {\n return;\n }\n\n this.logger.info(`[${stage} stage] Start executing shutdown stage ${stage}...`);\n const results = await Promise.allSettled(tasks.map(t => t.fn()));\n results.forEach((result, index) => {\n if (result.status === 'rejected') {\n const { name } = tasks[index];\n this.logger.error(`[${stage} stage] Failed to shutdown '${name}'`, { error: result.reason });\n }\n });\n this.logger.info(`[${stage} stage] Shutdown stage ${stage} completed`);\n }\n\n /**\n * Triggers graceful shutdown process\n * Can be called manually or automatically via SIGTERM/SIGINT signal handlers\n *\n * Shutdown happens in three stages:\n * 1. stopAcceptingWork - Stop accepting new requests/work\n * 2. drain - Allow in-flight work to complete\n * 3. close - Close all connections and clean up resources\n *\n * @param signal - Signal name (e.g., 'SIGTERM', 'SIGINT', 'MANUAL')\n */\n async shutdown(signal = 'MANUAL'): Promise<void> {\n try {\n if (this.isShuttingDown) {\n this.logger.warn('Shutdown already in progress');\n return;\n }\n\n const { shutdownDelayMs, useExit0, onShutdown, beforeShutdown } = this.config;\n\n this.logger.info(`${signal} received: setting readiness state to false`);\n\n this.isShuttingDown = true;\n this.isReady = false;\n\n await beforeShutdown?.();\n\n this.logger.info(`Waiting ${shutdownDelayMs}ms before shutdown...`);\n await setTimeout(shutdownDelayMs);\n\n const shutdownTasksByStage = this.groupShutdownTasksByStage(signal);\n\n await this.executeShutdownStage(SHUTDOWN_STAGES.STOP_ACCEPTING_WORK, shutdownTasksByStage[SHUTDOWN_STAGES.STOP_ACCEPTING_WORK]);\n\n // Wait between stages to allow in-flight work to complete (we are missing a drain stage in our rabbitmq package)\n // TODO once we have proper drain handlers, we can remove this fixed wait\n this.logger.info('Waiting 2000ms to allow in-flight work to complete...');\n await setTimeout(2_000);\n\n await this.executeShutdownStage(SHUTDOWN_STAGES.DRAIN, shutdownTasksByStage[SHUTDOWN_STAGES.DRAIN]);\n await this.executeShutdownStage(SHUTDOWN_STAGES.CLOSE, shutdownTasksByStage[SHUTDOWN_STAGES.CLOSE]);\n\n await onShutdown?.();\n\n this.logger.info('Shutdown process completed');\n\n if (useExit0) {\n this.logger.info(`Exiting process after ${signal}`);\n process.exit(0);\n }\n } catch (error: any) {\n this.logger.error('Error during shutdown process, forcing process exit despite shutdown error', { error, signal });\n process.exit(1);\n }\n }\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- const e=require(`./types.cjs`),t=(e,t)=>{let n={};for(let[r,i]of Object.entries(t))n[r]=async({client:t,name:n,signal:a,logger:o})=>{let s=i(t,a);if(!s){o.warn(`${e} client '${n}' does not have a shutdown method for stage '${r}', skipping`);return}try{o.info(`[${r} stage] Shutting down ${e.toLowerCase()} client '${n}'...`),await s}catch(t){throw o.error(`[${r} stage] Failed to shutdown ${e.toLowerCase()} client '${n}'`,{error:t}),t}};return n},n={[e.CLIENT_TYPES.REDIS]:t(`Redis`,{[e.SHUTDOWN_STAGES.CLOSE]:e=>e.quit?.()}),[e.CLIENT_TYPES.SEQUELIZE]:t(`Sequelize`,{[e.SHUTDOWN_STAGES.CLOSE]:e=>e.close?.()}),[e.CLIENT_TYPES.ELASTIC_SEARCH]:t(`Elasticsearch`,{[e.SHUTDOWN_STAGES.CLOSE]:e=>e.close?.()}),[e.CLIENT_TYPES.RABBIT]:t(`RabbitMQ`,{[e.SHUTDOWN_STAGES.STOP_ACCEPTING_WORK]:(e,t)=>e.gracefulShutdown?.(t)}),[e.CLIENT_TYPES.EVENTS]:t(`Events`,{[e.SHUTDOWN_STAGES.CLOSE]:(e,t)=>e.exitHandler?.(t)}),[e.CLIENT_TYPES.SERVER]:{[e.SHUTDOWN_STAGES.STOP_ACCEPTING_WORK]:async({logger:e,customHandlersPayload:t})=>{let{httpTerminator:n}=t||{};try{if(!n){e.warn(`[stopAcceptingWork] No httpTerminator provided in customHandlersPayload, skipping server shutdown`);return}e.info(`[stopAcceptingWork] Shutting down server...`),await n.terminate()}catch(t){throw e.error(`[stopAcceptingWork] Failed to shutdown server: ${t instanceof Error?t.message:String(t)}`),t}}}};exports.DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP=n;
1
+ const e=require(`./types.cjs`),t=(e,t)=>{let n={};for(let[r,i]of Object.entries(t))n[r]=async({client:t,name:n,signal:a,logger:o})=>{let s=i(t,a);if(!s){o.warn(`${e} client '${n}' does not have a shutdown method for stage '${r}', skipping`);return}try{o.info(`[${r} stage] Shutting down ${e.toLowerCase()} client '${n}'...`),await s}catch(t){throw o.error(`[${r} stage] Failed to shutdown ${e.toLowerCase()} client '${n}'`,{error:t}),t}};return n},n={[e.CLIENT_TYPES.REDIS]:t(`Redis`,{[e.SHUTDOWN_STAGES.CLOSE]:e=>e.quit?.()}),[e.CLIENT_TYPES.SEQUELIZE]:t(`Sequelize`,{[e.SHUTDOWN_STAGES.CLOSE]:e=>e.close?.()}),[e.CLIENT_TYPES.ELASTIC_SEARCH]:t(`Elasticsearch`,{[e.SHUTDOWN_STAGES.CLOSE]:e=>e.close?.()}),[e.CLIENT_TYPES.RABBIT]:t(`RabbitMQ`,{[e.SHUTDOWN_STAGES.STOP_ACCEPTING_WORK]:(e,t)=>e.gracefulShutdown?.(t)}),[e.CLIENT_TYPES.EVENTS]:t(`Events`,{[e.SHUTDOWN_STAGES.CLOSE]:(e,t)=>e.exitHandler?.(t)}),[e.CLIENT_TYPES.SERVER]:{[e.SHUTDOWN_STAGES.STOP_ACCEPTING_WORK]:async({logger:e,customHandlersPayload:t})=>{let{httpTerminator:n}=t||{};try{if(!n){e.warn(`[stopAcceptingWork stage] No httpTerminator provided in customHandlersPayload, skipping server shutdown`);return}e.info(`[stopAcceptingWork stage] Shutting down server...`),await n.terminate()}catch(t){throw e.error(`[stopAcceptingWork] Failed to shutdown server: ${t instanceof Error?t.message:String(t)}`),t}}}};exports.DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP=n;
2
2
  //# sourceMappingURL=shutdown-handlers.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"shutdown-handlers.cjs","names":["handlers: ShutdownHandlersByStage","DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP: Partial<Record<ClientType, ShutdownHandlersByStage>>","CLIENT_TYPES","SHUTDOWN_STAGES"],"sources":["../../src/health-manager/shutdown-handlers.ts"],"sourcesContent":["import type {\n HttpTerminator,\n} from 'http-terminator';\nimport type {\n ClientType,\n RedisClient,\n SequelizeClient,\n ElasticsearchClient,\n RabbitMQClient,\n EventsClient,\n ShutdownHandlersByStage,\n ShutdownStage,\n} from './types';\nimport { CLIENT_TYPES, SHUTDOWN_STAGES } from './types';\n\nconst createShutdownHandlers = <T>(\n clientType: string,\n shutdownHandlersByStage: Partial<Record<ShutdownStage, (client: T, signal?: string) => Promise<void> | undefined>>,\n): ShutdownHandlersByStage => {\n const handlers: ShutdownHandlersByStage = {};\n\n for (const [stage, shutdownHandler] of Object.entries(shutdownHandlersByStage) as [ShutdownStage, (client: T, signal?: string) => Promise<void> | undefined][]) {\n handlers[stage] = async ({ client, name, signal, logger }) => {\n const shutdownFn = shutdownHandler(client, signal);\n if (!shutdownFn) {\n logger.warn(`${clientType} client '${name}' does not have a shutdown method for stage '${stage}', skipping`);\n return;\n }\n try {\n logger.info(`[${stage} stage] Shutting down ${clientType.toLowerCase()} client '${name}'...`);\n await shutdownFn;\n } catch (error) {\n logger.error(`[${stage} stage] Failed to shutdown ${clientType.toLowerCase()} client '${name}'`, { error });\n throw error;\n }\n };\n }\n\n return handlers;\n};\n\nexport const DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP: Partial<Record<ClientType, ShutdownHandlersByStage>> = {\n [CLIENT_TYPES.REDIS]: createShutdownHandlers<RedisClient>('Redis', {\n [SHUTDOWN_STAGES.CLOSE]: client => client.quit?.(),\n }),\n [CLIENT_TYPES.SEQUELIZE]: createShutdownHandlers<SequelizeClient>('Sequelize', {\n [SHUTDOWN_STAGES.CLOSE]: client => client.close?.(),\n }),\n [CLIENT_TYPES.ELASTIC_SEARCH]: createShutdownHandlers<ElasticsearchClient>('Elasticsearch', {\n [SHUTDOWN_STAGES.CLOSE]: client => client.close?.(),\n }),\n [CLIENT_TYPES.RABBIT]: createShutdownHandlers<RabbitMQClient>('RabbitMQ', {\n [SHUTDOWN_STAGES.STOP_ACCEPTING_WORK]: (client, signal) => client.gracefulShutdown?.(signal),\n }),\n [CLIENT_TYPES.EVENTS]: createShutdownHandlers<EventsClient>('Events', {\n [SHUTDOWN_STAGES.CLOSE]: (client, signal) => client.exitHandler?.(signal),\n }),\n [CLIENT_TYPES.SERVER]: {\n [SHUTDOWN_STAGES.STOP_ACCEPTING_WORK]: async ({ logger, customHandlersPayload }) => {\n const { httpTerminator }: { httpTerminator?: HttpTerminator; } = customHandlersPayload || {};\n try {\n if (!httpTerminator) {\n logger.warn('[stopAcceptingWork] No httpTerminator provided in customHandlersPayload, skipping server shutdown');\n return;\n }\n logger.info('[stopAcceptingWork] Shutting down server...');\n await httpTerminator.terminate();\n } catch (error) {\n logger.error(`[stopAcceptingWork] Failed to shutdown server: ${error instanceof Error ? error.message : String(error)}`);\n throw error;\n }\n },\n },\n};\n"],"mappings":"+BAeM,GACJ,EACA,IAC4B,CAC5B,IAAMA,EAAoC,EAAE,CAE5C,IAAK,GAAM,CAAC,EAAO,KAAoB,OAAO,QAAQ,EAAwB,CAC5E,EAAS,GAAS,MAAO,CAAE,SAAQ,OAAM,SAAQ,YAAa,CAC5D,IAAM,EAAa,EAAgB,EAAQ,EAAO,CAClD,GAAI,CAAC,EAAY,CACf,EAAO,KAAK,GAAG,EAAW,WAAW,EAAK,+CAA+C,EAAM,aAAa,CAC5G,OAEF,GAAI,CACF,EAAO,KAAK,IAAI,EAAM,wBAAwB,EAAW,aAAa,CAAC,WAAW,EAAK,MAAM,CAC7F,MAAM,QACC,EAAO,CAEd,MADA,EAAO,MAAM,IAAI,EAAM,6BAA6B,EAAW,aAAa,CAAC,WAAW,EAAK,GAAI,CAAE,QAAO,CAAC,CACrG,IAKZ,OAAO,GAGIC,EAA6F,EACvGC,EAAAA,aAAa,OAAQ,EAAoC,QAAS,EAChEC,EAAAA,gBAAgB,OAAQ,GAAU,EAAO,QAAQ,CACnD,CAAC,EACDD,EAAAA,aAAa,WAAY,EAAwC,YAAa,EAC5EC,EAAAA,gBAAgB,OAAQ,GAAU,EAAO,SAAS,CACpD,CAAC,EACDD,EAAAA,aAAa,gBAAiB,EAA4C,gBAAiB,EACzFC,EAAAA,gBAAgB,OAAQ,GAAU,EAAO,SAAS,CACpD,CAAC,EACDD,EAAAA,aAAa,QAAS,EAAuC,WAAY,EACvEC,EAAAA,gBAAgB,sBAAuB,EAAQ,IAAW,EAAO,mBAAmB,EAAO,CAC7F,CAAC,EACDD,EAAAA,aAAa,QAAS,EAAqC,SAAU,EACnEC,EAAAA,gBAAgB,QAAS,EAAQ,IAAW,EAAO,cAAc,EAAO,CAC1E,CAAC,EACDD,EAAAA,aAAa,QAAS,EACpBC,EAAAA,gBAAgB,qBAAsB,MAAO,CAAE,SAAQ,2BAA4B,CAClF,GAAM,CAAE,kBAAyD,GAAyB,EAAE,CAC5F,GAAI,CACF,GAAI,CAAC,EAAgB,CACnB,EAAO,KAAK,oGAAoG,CAChH,OAEF,EAAO,KAAK,8CAA8C,CAC1D,MAAM,EAAe,WAAW,OACzB,EAAO,CAEd,MADA,EAAO,MAAM,kDAAkD,aAAiB,MAAQ,EAAM,QAAU,OAAO,EAAM,GAAG,CAClH,IAGX,CACF"}
1
+ {"version":3,"file":"shutdown-handlers.cjs","names":["handlers: ShutdownHandlersByStage<T>","DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP: Partial<Record<ClientType, ShutdownHandlersByStage<any>>>","CLIENT_TYPES","SHUTDOWN_STAGES"],"sources":["../../src/health-manager/shutdown-handlers.ts"],"sourcesContent":["import type {\n HttpTerminator,\n} from 'http-terminator';\nimport type {\n ClientType,\n RedisClient,\n SequelizeClient,\n ElasticsearchClient,\n RabbitMQClient,\n EventsClient,\n ShutdownHandlersByStage,\n ShutdownStage,\n} from './types';\nimport { CLIENT_TYPES, SHUTDOWN_STAGES } from './types';\n\nconst createShutdownHandlers = <T>(\n clientType: string,\n shutdownHandlersByStage: Partial<Record<ShutdownStage, (client: T, signal?: string) => Promise<void> | undefined>>,\n): ShutdownHandlersByStage<T> => {\n const handlers: ShutdownHandlersByStage<T> = {};\n\n for (const [stage, shutdownHandler] of Object.entries(shutdownHandlersByStage) as [ShutdownStage, (client: T, signal?: string) => Promise<void> | undefined][]) {\n handlers[stage] = async ({ client, name, signal, logger }) => {\n const shutdownFn = shutdownHandler(client, signal);\n if (!shutdownFn) {\n logger.warn(`${clientType} client '${name}' does not have a shutdown method for stage '${stage}', skipping`);\n return;\n }\n try {\n logger.info(`[${stage} stage] Shutting down ${clientType.toLowerCase()} client '${name}'...`);\n await shutdownFn;\n } catch (error) {\n logger.error(`[${stage} stage] Failed to shutdown ${clientType.toLowerCase()} client '${name}'`, { error });\n throw error;\n }\n };\n }\n\n return handlers;\n};\n\nexport const DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP: Partial<Record<ClientType, ShutdownHandlersByStage<any>>> = {\n [CLIENT_TYPES.REDIS]: createShutdownHandlers<RedisClient>('Redis', {\n [SHUTDOWN_STAGES.CLOSE]: client => client.quit?.(),\n }),\n [CLIENT_TYPES.SEQUELIZE]: createShutdownHandlers<SequelizeClient>('Sequelize', {\n [SHUTDOWN_STAGES.CLOSE]: client => client.close?.(),\n }),\n [CLIENT_TYPES.ELASTIC_SEARCH]: createShutdownHandlers<ElasticsearchClient>('Elasticsearch', {\n [SHUTDOWN_STAGES.CLOSE]: client => client.close?.(),\n }),\n [CLIENT_TYPES.RABBIT]: createShutdownHandlers<RabbitMQClient>('RabbitMQ', {\n [SHUTDOWN_STAGES.STOP_ACCEPTING_WORK]: (client, signal) => client.gracefulShutdown?.(signal),\n }),\n [CLIENT_TYPES.EVENTS]: createShutdownHandlers<EventsClient>('Events', {\n [SHUTDOWN_STAGES.CLOSE]: (client, signal) => client.exitHandler?.(signal),\n }),\n [CLIENT_TYPES.SERVER]: {\n [SHUTDOWN_STAGES.STOP_ACCEPTING_WORK]: async ({ logger, customHandlersPayload }) => {\n const { httpTerminator }: { httpTerminator?: HttpTerminator; } = customHandlersPayload || {};\n try {\n if (!httpTerminator) {\n logger.warn('[stopAcceptingWork stage] No httpTerminator provided in customHandlersPayload, skipping server shutdown');\n return;\n }\n logger.info('[stopAcceptingWork stage] Shutting down server...');\n await httpTerminator.terminate();\n } catch (error) {\n logger.error(`[stopAcceptingWork] Failed to shutdown server: ${error instanceof Error ? error.message : String(error)}`);\n throw error;\n }\n },\n },\n};\n"],"mappings":"+BAeM,GACJ,EACA,IAC+B,CAC/B,IAAMA,EAAuC,EAAE,CAE/C,IAAK,GAAM,CAAC,EAAO,KAAoB,OAAO,QAAQ,EAAwB,CAC5E,EAAS,GAAS,MAAO,CAAE,SAAQ,OAAM,SAAQ,YAAa,CAC5D,IAAM,EAAa,EAAgB,EAAQ,EAAO,CAClD,GAAI,CAAC,EAAY,CACf,EAAO,KAAK,GAAG,EAAW,WAAW,EAAK,+CAA+C,EAAM,aAAa,CAC5G,OAEF,GAAI,CACF,EAAO,KAAK,IAAI,EAAM,wBAAwB,EAAW,aAAa,CAAC,WAAW,EAAK,MAAM,CAC7F,MAAM,QACC,EAAO,CAEd,MADA,EAAO,MAAM,IAAI,EAAM,6BAA6B,EAAW,aAAa,CAAC,WAAW,EAAK,GAAI,CAAE,QAAO,CAAC,CACrG,IAKZ,OAAO,GAGIC,EAAkG,EAC5GC,EAAAA,aAAa,OAAQ,EAAoC,QAAS,EAChEC,EAAAA,gBAAgB,OAAQ,GAAU,EAAO,QAAQ,CACnD,CAAC,EACDD,EAAAA,aAAa,WAAY,EAAwC,YAAa,EAC5EC,EAAAA,gBAAgB,OAAQ,GAAU,EAAO,SAAS,CACpD,CAAC,EACDD,EAAAA,aAAa,gBAAiB,EAA4C,gBAAiB,EACzFC,EAAAA,gBAAgB,OAAQ,GAAU,EAAO,SAAS,CACpD,CAAC,EACDD,EAAAA,aAAa,QAAS,EAAuC,WAAY,EACvEC,EAAAA,gBAAgB,sBAAuB,EAAQ,IAAW,EAAO,mBAAmB,EAAO,CAC7F,CAAC,EACDD,EAAAA,aAAa,QAAS,EAAqC,SAAU,EACnEC,EAAAA,gBAAgB,QAAS,EAAQ,IAAW,EAAO,cAAc,EAAO,CAC1E,CAAC,EACDD,EAAAA,aAAa,QAAS,EACpBC,EAAAA,gBAAgB,qBAAsB,MAAO,CAAE,SAAQ,2BAA4B,CAClF,GAAM,CAAE,kBAAyD,GAAyB,EAAE,CAC5F,GAAI,CACF,GAAI,CAAC,EAAgB,CACnB,EAAO,KAAK,0GAA0G,CACtH,OAEF,EAAO,KAAK,oDAAoD,CAChE,MAAM,EAAe,WAAW,OACzB,EAAO,CAEd,MADA,EAAO,MAAM,kDAAkD,aAAiB,MAAQ,EAAM,QAAU,OAAO,EAAM,GAAG,CAClH,IAGX,CACF"}
@@ -1,2 +1,2 @@
1
- import{CLIENT_TYPES as e,SHUTDOWN_STAGES as t}from"./types.js";const n=(e,t)=>{let n={};for(let[r,i]of Object.entries(t))n[r]=async({client:t,name:n,signal:a,logger:o})=>{let s=i(t,a);if(!s){o.warn(`${e} client '${n}' does not have a shutdown method for stage '${r}', skipping`);return}try{o.info(`[${r} stage] Shutting down ${e.toLowerCase()} client '${n}'...`),await s}catch(t){throw o.error(`[${r} stage] Failed to shutdown ${e.toLowerCase()} client '${n}'`,{error:t}),t}};return n},r={[e.REDIS]:n(`Redis`,{[t.CLOSE]:e=>e.quit?.()}),[e.SEQUELIZE]:n(`Sequelize`,{[t.CLOSE]:e=>e.close?.()}),[e.ELASTIC_SEARCH]:n(`Elasticsearch`,{[t.CLOSE]:e=>e.close?.()}),[e.RABBIT]:n(`RabbitMQ`,{[t.STOP_ACCEPTING_WORK]:(e,t)=>e.gracefulShutdown?.(t)}),[e.EVENTS]:n(`Events`,{[t.CLOSE]:(e,t)=>e.exitHandler?.(t)}),[e.SERVER]:{[t.STOP_ACCEPTING_WORK]:async({logger:e,customHandlersPayload:t})=>{let{httpTerminator:n}=t||{};try{if(!n){e.warn(`[stopAcceptingWork] No httpTerminator provided in customHandlersPayload, skipping server shutdown`);return}e.info(`[stopAcceptingWork] Shutting down server...`),await n.terminate()}catch(t){throw e.error(`[stopAcceptingWork] Failed to shutdown server: ${t instanceof Error?t.message:String(t)}`),t}}}};export{r as DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP};
1
+ import{CLIENT_TYPES as e,SHUTDOWN_STAGES as t}from"./types.js";const n=(e,t)=>{let n={};for(let[r,i]of Object.entries(t))n[r]=async({client:t,name:n,signal:a,logger:o})=>{let s=i(t,a);if(!s){o.warn(`${e} client '${n}' does not have a shutdown method for stage '${r}', skipping`);return}try{o.info(`[${r} stage] Shutting down ${e.toLowerCase()} client '${n}'...`),await s}catch(t){throw o.error(`[${r} stage] Failed to shutdown ${e.toLowerCase()} client '${n}'`,{error:t}),t}};return n},r={[e.REDIS]:n(`Redis`,{[t.CLOSE]:e=>e.quit?.()}),[e.SEQUELIZE]:n(`Sequelize`,{[t.CLOSE]:e=>e.close?.()}),[e.ELASTIC_SEARCH]:n(`Elasticsearch`,{[t.CLOSE]:e=>e.close?.()}),[e.RABBIT]:n(`RabbitMQ`,{[t.STOP_ACCEPTING_WORK]:(e,t)=>e.gracefulShutdown?.(t)}),[e.EVENTS]:n(`Events`,{[t.CLOSE]:(e,t)=>e.exitHandler?.(t)}),[e.SERVER]:{[t.STOP_ACCEPTING_WORK]:async({logger:e,customHandlersPayload:t})=>{let{httpTerminator:n}=t||{};try{if(!n){e.warn(`[stopAcceptingWork stage] No httpTerminator provided in customHandlersPayload, skipping server shutdown`);return}e.info(`[stopAcceptingWork stage] Shutting down server...`),await n.terminate()}catch(t){throw e.error(`[stopAcceptingWork] Failed to shutdown server: ${t instanceof Error?t.message:String(t)}`),t}}}};export{r as DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP};
2
2
  //# sourceMappingURL=shutdown-handlers.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"shutdown-handlers.js","names":["handlers: ShutdownHandlersByStage","DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP: Partial<Record<ClientType, ShutdownHandlersByStage>>"],"sources":["../../src/health-manager/shutdown-handlers.ts"],"sourcesContent":["import type {\n HttpTerminator,\n} from 'http-terminator';\nimport type {\n ClientType,\n RedisClient,\n SequelizeClient,\n ElasticsearchClient,\n RabbitMQClient,\n EventsClient,\n ShutdownHandlersByStage,\n ShutdownStage,\n} from './types';\nimport { CLIENT_TYPES, SHUTDOWN_STAGES } from './types';\n\nconst createShutdownHandlers = <T>(\n clientType: string,\n shutdownHandlersByStage: Partial<Record<ShutdownStage, (client: T, signal?: string) => Promise<void> | undefined>>,\n): ShutdownHandlersByStage => {\n const handlers: ShutdownHandlersByStage = {};\n\n for (const [stage, shutdownHandler] of Object.entries(shutdownHandlersByStage) as [ShutdownStage, (client: T, signal?: string) => Promise<void> | undefined][]) {\n handlers[stage] = async ({ client, name, signal, logger }) => {\n const shutdownFn = shutdownHandler(client, signal);\n if (!shutdownFn) {\n logger.warn(`${clientType} client '${name}' does not have a shutdown method for stage '${stage}', skipping`);\n return;\n }\n try {\n logger.info(`[${stage} stage] Shutting down ${clientType.toLowerCase()} client '${name}'...`);\n await shutdownFn;\n } catch (error) {\n logger.error(`[${stage} stage] Failed to shutdown ${clientType.toLowerCase()} client '${name}'`, { error });\n throw error;\n }\n };\n }\n\n return handlers;\n};\n\nexport const DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP: Partial<Record<ClientType, ShutdownHandlersByStage>> = {\n [CLIENT_TYPES.REDIS]: createShutdownHandlers<RedisClient>('Redis', {\n [SHUTDOWN_STAGES.CLOSE]: client => client.quit?.(),\n }),\n [CLIENT_TYPES.SEQUELIZE]: createShutdownHandlers<SequelizeClient>('Sequelize', {\n [SHUTDOWN_STAGES.CLOSE]: client => client.close?.(),\n }),\n [CLIENT_TYPES.ELASTIC_SEARCH]: createShutdownHandlers<ElasticsearchClient>('Elasticsearch', {\n [SHUTDOWN_STAGES.CLOSE]: client => client.close?.(),\n }),\n [CLIENT_TYPES.RABBIT]: createShutdownHandlers<RabbitMQClient>('RabbitMQ', {\n [SHUTDOWN_STAGES.STOP_ACCEPTING_WORK]: (client, signal) => client.gracefulShutdown?.(signal),\n }),\n [CLIENT_TYPES.EVENTS]: createShutdownHandlers<EventsClient>('Events', {\n [SHUTDOWN_STAGES.CLOSE]: (client, signal) => client.exitHandler?.(signal),\n }),\n [CLIENT_TYPES.SERVER]: {\n [SHUTDOWN_STAGES.STOP_ACCEPTING_WORK]: async ({ logger, customHandlersPayload }) => {\n const { httpTerminator }: { httpTerminator?: HttpTerminator; } = customHandlersPayload || {};\n try {\n if (!httpTerminator) {\n logger.warn('[stopAcceptingWork] No httpTerminator provided in customHandlersPayload, skipping server shutdown');\n return;\n }\n logger.info('[stopAcceptingWork] Shutting down server...');\n await httpTerminator.terminate();\n } catch (error) {\n logger.error(`[stopAcceptingWork] Failed to shutdown server: ${error instanceof Error ? error.message : String(error)}`);\n throw error;\n }\n },\n },\n};\n"],"mappings":"+DAeA,MAAM,GACJ,EACA,IAC4B,CAC5B,IAAMA,EAAoC,EAAE,CAE5C,IAAK,GAAM,CAAC,EAAO,KAAoB,OAAO,QAAQ,EAAwB,CAC5E,EAAS,GAAS,MAAO,CAAE,SAAQ,OAAM,SAAQ,YAAa,CAC5D,IAAM,EAAa,EAAgB,EAAQ,EAAO,CAClD,GAAI,CAAC,EAAY,CACf,EAAO,KAAK,GAAG,EAAW,WAAW,EAAK,+CAA+C,EAAM,aAAa,CAC5G,OAEF,GAAI,CACF,EAAO,KAAK,IAAI,EAAM,wBAAwB,EAAW,aAAa,CAAC,WAAW,EAAK,MAAM,CAC7F,MAAM,QACC,EAAO,CAEd,MADA,EAAO,MAAM,IAAI,EAAM,6BAA6B,EAAW,aAAa,CAAC,WAAW,EAAK,GAAI,CAAE,QAAO,CAAC,CACrG,IAKZ,OAAO,GAGIC,EAA6F,EACvG,EAAa,OAAQ,EAAoC,QAAS,EAChE,EAAgB,OAAQ,GAAU,EAAO,QAAQ,CACnD,CAAC,EACD,EAAa,WAAY,EAAwC,YAAa,EAC5E,EAAgB,OAAQ,GAAU,EAAO,SAAS,CACpD,CAAC,EACD,EAAa,gBAAiB,EAA4C,gBAAiB,EACzF,EAAgB,OAAQ,GAAU,EAAO,SAAS,CACpD,CAAC,EACD,EAAa,QAAS,EAAuC,WAAY,EACvE,EAAgB,sBAAuB,EAAQ,IAAW,EAAO,mBAAmB,EAAO,CAC7F,CAAC,EACD,EAAa,QAAS,EAAqC,SAAU,EACnE,EAAgB,QAAS,EAAQ,IAAW,EAAO,cAAc,EAAO,CAC1E,CAAC,EACD,EAAa,QAAS,EACpB,EAAgB,qBAAsB,MAAO,CAAE,SAAQ,2BAA4B,CAClF,GAAM,CAAE,kBAAyD,GAAyB,EAAE,CAC5F,GAAI,CACF,GAAI,CAAC,EAAgB,CACnB,EAAO,KAAK,oGAAoG,CAChH,OAEF,EAAO,KAAK,8CAA8C,CAC1D,MAAM,EAAe,WAAW,OACzB,EAAO,CAEd,MADA,EAAO,MAAM,kDAAkD,aAAiB,MAAQ,EAAM,QAAU,OAAO,EAAM,GAAG,CAClH,IAGX,CACF"}
1
+ {"version":3,"file":"shutdown-handlers.js","names":["handlers: ShutdownHandlersByStage<T>","DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP: Partial<Record<ClientType, ShutdownHandlersByStage<any>>>"],"sources":["../../src/health-manager/shutdown-handlers.ts"],"sourcesContent":["import type {\n HttpTerminator,\n} from 'http-terminator';\nimport type {\n ClientType,\n RedisClient,\n SequelizeClient,\n ElasticsearchClient,\n RabbitMQClient,\n EventsClient,\n ShutdownHandlersByStage,\n ShutdownStage,\n} from './types';\nimport { CLIENT_TYPES, SHUTDOWN_STAGES } from './types';\n\nconst createShutdownHandlers = <T>(\n clientType: string,\n shutdownHandlersByStage: Partial<Record<ShutdownStage, (client: T, signal?: string) => Promise<void> | undefined>>,\n): ShutdownHandlersByStage<T> => {\n const handlers: ShutdownHandlersByStage<T> = {};\n\n for (const [stage, shutdownHandler] of Object.entries(shutdownHandlersByStage) as [ShutdownStage, (client: T, signal?: string) => Promise<void> | undefined][]) {\n handlers[stage] = async ({ client, name, signal, logger }) => {\n const shutdownFn = shutdownHandler(client, signal);\n if (!shutdownFn) {\n logger.warn(`${clientType} client '${name}' does not have a shutdown method for stage '${stage}', skipping`);\n return;\n }\n try {\n logger.info(`[${stage} stage] Shutting down ${clientType.toLowerCase()} client '${name}'...`);\n await shutdownFn;\n } catch (error) {\n logger.error(`[${stage} stage] Failed to shutdown ${clientType.toLowerCase()} client '${name}'`, { error });\n throw error;\n }\n };\n }\n\n return handlers;\n};\n\nexport const DEFAULT_CLIENT_SHUTDOWN_HANDLERS_MAP: Partial<Record<ClientType, ShutdownHandlersByStage<any>>> = {\n [CLIENT_TYPES.REDIS]: createShutdownHandlers<RedisClient>('Redis', {\n [SHUTDOWN_STAGES.CLOSE]: client => client.quit?.(),\n }),\n [CLIENT_TYPES.SEQUELIZE]: createShutdownHandlers<SequelizeClient>('Sequelize', {\n [SHUTDOWN_STAGES.CLOSE]: client => client.close?.(),\n }),\n [CLIENT_TYPES.ELASTIC_SEARCH]: createShutdownHandlers<ElasticsearchClient>('Elasticsearch', {\n [SHUTDOWN_STAGES.CLOSE]: client => client.close?.(),\n }),\n [CLIENT_TYPES.RABBIT]: createShutdownHandlers<RabbitMQClient>('RabbitMQ', {\n [SHUTDOWN_STAGES.STOP_ACCEPTING_WORK]: (client, signal) => client.gracefulShutdown?.(signal),\n }),\n [CLIENT_TYPES.EVENTS]: createShutdownHandlers<EventsClient>('Events', {\n [SHUTDOWN_STAGES.CLOSE]: (client, signal) => client.exitHandler?.(signal),\n }),\n [CLIENT_TYPES.SERVER]: {\n [SHUTDOWN_STAGES.STOP_ACCEPTING_WORK]: async ({ logger, customHandlersPayload }) => {\n const { httpTerminator }: { httpTerminator?: HttpTerminator; } = customHandlersPayload || {};\n try {\n if (!httpTerminator) {\n logger.warn('[stopAcceptingWork stage] No httpTerminator provided in customHandlersPayload, skipping server shutdown');\n return;\n }\n logger.info('[stopAcceptingWork stage] Shutting down server...');\n await httpTerminator.terminate();\n } catch (error) {\n logger.error(`[stopAcceptingWork] Failed to shutdown server: ${error instanceof Error ? error.message : String(error)}`);\n throw error;\n }\n },\n },\n};\n"],"mappings":"+DAeA,MAAM,GACJ,EACA,IAC+B,CAC/B,IAAMA,EAAuC,EAAE,CAE/C,IAAK,GAAM,CAAC,EAAO,KAAoB,OAAO,QAAQ,EAAwB,CAC5E,EAAS,GAAS,MAAO,CAAE,SAAQ,OAAM,SAAQ,YAAa,CAC5D,IAAM,EAAa,EAAgB,EAAQ,EAAO,CAClD,GAAI,CAAC,EAAY,CACf,EAAO,KAAK,GAAG,EAAW,WAAW,EAAK,+CAA+C,EAAM,aAAa,CAC5G,OAEF,GAAI,CACF,EAAO,KAAK,IAAI,EAAM,wBAAwB,EAAW,aAAa,CAAC,WAAW,EAAK,MAAM,CAC7F,MAAM,QACC,EAAO,CAEd,MADA,EAAO,MAAM,IAAI,EAAM,6BAA6B,EAAW,aAAa,CAAC,WAAW,EAAK,GAAI,CAAE,QAAO,CAAC,CACrG,IAKZ,OAAO,GAGIC,EAAkG,EAC5G,EAAa,OAAQ,EAAoC,QAAS,EAChE,EAAgB,OAAQ,GAAU,EAAO,QAAQ,CACnD,CAAC,EACD,EAAa,WAAY,EAAwC,YAAa,EAC5E,EAAgB,OAAQ,GAAU,EAAO,SAAS,CACpD,CAAC,EACD,EAAa,gBAAiB,EAA4C,gBAAiB,EACzF,EAAgB,OAAQ,GAAU,EAAO,SAAS,CACpD,CAAC,EACD,EAAa,QAAS,EAAuC,WAAY,EACvE,EAAgB,sBAAuB,EAAQ,IAAW,EAAO,mBAAmB,EAAO,CAC7F,CAAC,EACD,EAAa,QAAS,EAAqC,SAAU,EACnE,EAAgB,QAAS,EAAQ,IAAW,EAAO,cAAc,EAAO,CAC1E,CAAC,EACD,EAAa,QAAS,EACpB,EAAgB,qBAAsB,MAAO,CAAE,SAAQ,2BAA4B,CAClF,GAAM,CAAE,kBAAyD,GAAyB,EAAE,CAC5F,GAAI,CACF,GAAI,CAAC,EAAgB,CACnB,EAAO,KAAK,0GAA0G,CACtH,OAEF,EAAO,KAAK,oDAAoD,CAChE,MAAM,EAAe,WAAW,OACzB,EAAO,CAEd,MADA,EAAO,MAAM,kDAAkD,aAAiB,MAAQ,EAAM,QAAU,OAAO,EAAM,GAAG,CAClH,IAGX,CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"types.cjs","names":[],"sources":["../../src/health-manager/types.ts"],"sourcesContent":["import type { LoggerInstanceManager } from '@autofleet/logger';\nimport type { Server as HttpServer } from 'node:http';\nimport type { Server as HttpsServer } from 'node:https';\n\nexport type HealthCheckHandler = (options: {\n client: any;\n name: string;\n customHandlersPayload?: any;\n logger: LoggerInstanceManager;\n}) => Promise<void>;\n\nexport type ShutdownHandler = (options: {\n client: any;\n name: string;\n signal?: string;\n customHandlersPayload?: any;\n logger: LoggerInstanceManager;\n}) => Promise<void>;\n\nexport type ShutdownHandlersByStage = Partial<Record<ShutdownStage, ShutdownHandler>>;\n\nexport const SHUTDOWN_STAGES = {\n STOP_ACCEPTING_WORK: 'stopAcceptingWork',\n DRAIN: 'drain',\n CLOSE: 'close',\n} as const;\n\nexport type ShutdownStage = typeof SHUTDOWN_STAGES[keyof typeof SHUTDOWN_STAGES];\n\n/**\n * Configuration for a single client (e.g., rabbit, sequelize, redis, elasticsearch)\n * Allows custom health checks and shutdown logic\n */\nexport interface ClientConfig<T = any, TPayload = any> {\n /** The actual connection instance */\n connection: T;\n\n /** Custom health check function (optional) - will be called during alive/ready checks with client connection and name */\n healthCheck?: HealthCheckHandler;\n\n /** Custom shutdown handlers by stage (optional) - will be called during graceful shutdown at appropriate stages */\n shutdownHandlers?: ShutdownHandlersByStage;\n\n /** Additional options specific to the client (optional) */\n options?: {\n /** Whether to include this client in liveness checks (default: true) */\n includeInLivenessCheck?: boolean;\n\n /** Whether to include this client in readiness checks (default: true) */\n includeInReadinessCheck?: boolean;\n\n /** Custom name for this client (used in logging) */\n name?: string;\n\n /** Custom payload to pass to health check and shutdown handlers - use this to pass any additional data your handlers need */\n customHandlersPayload?: TPayload;\n\n /** Which shutdown stages this client participates in */\n shutdownStages?: ShutdownStage[];\n };\n}\n\n/** Type alias for server configuration - uses ClientConfig with server instance */\nexport type ServerConfig = ClientConfig<HttpServer | HttpsServer>;\n\n/**\n * General configuration options for the HealthManager\n */\nexport interface HealthManagerConfig {\n /**\n * Delay in milliseconds before shutting down after SIGTERM/SIGINT\n * This gives time for load balancers to stop routing traffic. Should be equal to or greater than readiness probe interval.\n * @default 8000\n */\n shutdownDelayMs?: number;\n\n /**\n * Whether to call process.exit(0) after shutdown sequence completes\n * @default true\n */\n useExit0?: boolean;\n\n /** Whether to auto-setup SIGTERM/SIGINT handlers for graceful shutdown\n * @default true\n */\n shouldSetupSignalHandlers?: boolean;\n\n /**\n * Global shutdown hook called before all clients are shut down\n * @default undefined\n */\n beforeShutdown?: (() => Promise<void>) | undefined;\n\n /**\n * Global shutdown hook called after all clients are shut down\n * @default undefined\n */\n onShutdown?: (() => Promise<void>) | undefined;\n\n /**\n * Enable liveness check optimization - if true and all clients are in both liveness and readiness checks,\n * liveness checks will be skipped when pod is already ready (readiness check passed)\n * @default true\n */\n enableLivenessOptimization?: boolean;\n}\n\n/**\n * List of clients and general configuration for HealthManager\n */\nexport interface HealthManagerOptions {\n /** Client configurations */\n clients?: {\n /** RabbitMQ client configuration - can be a single config or array of configs */\n rabbit?: ClientConfig<any> | ClientConfig<any>[];\n\n /** Sequelize instance configuration - can be a single config or array of configs */\n sequelize?: ClientConfig<any> | ClientConfig<any>[];\n\n /** Redis client configuration - can be a single config or array of configs */\n redis?: ClientConfig<any> | ClientConfig<any>[];\n\n /** Elasticsearch client configuration - can be a single config or array of configs */\n elasticsearch?: ClientConfig<any> | ClientConfig<any>[];\n\n /** Events client configuration - can be a single config or array of configs */\n events?: ClientConfig<any> | ClientConfig<any>[];\n\n /** HTTP/HTTPS server configuration - can be a single config or array of configs */\n server?: ServerConfig | ServerConfig[];\n\n /** Custom client configurations - for any client type not explicitly listed above */\n [key: string]: ClientConfig<any> | ClientConfig<any>[] | undefined;\n };\n\n /** General configuration options */\n config?: HealthManagerConfig;\n\n /** Logger instance for logging messages */\n logger: LoggerInstanceManager;\n}\n\nexport interface RedisClient {\n ping?: () => Promise<string | void>;\n quit?: () => Promise<void>;\n}\n\n/**\n * Sequelize database interface\n */\nexport interface SequelizeClient {\n query?(sql: string | { query: string; values: unknown[]; }): Promise<any>;\n close?: () => Promise<void>;\n}\n\n/**\n * Elasticsearch client interface\n */\nexport interface ElasticsearchClient {\n ping?: () => Promise<boolean>;\n close?: () => Promise<void>;\n}\n\nexport interface EventsClient {\n exitHandler?: (signal?: string) => Promise<void>;\n}\n\n/**\n * RabbitMQ client interface\n */\nexport interface RabbitMQClient {\n isConnected?: () => Promise<boolean> | boolean;\n gracefulShutdown?: (signal?: string) => Promise<void>;\n}\n\nexport const CLIENT_TYPES = {\n RABBIT: 'rabbit',\n SEQUELIZE: 'sequelize',\n REDIS: 'redis',\n ELASTIC_SEARCH: 'elasticsearch',\n EVENTS: 'events',\n SERVER: 'server',\n CUSTOM: 'custom',\n} as const;\n\nexport type ClientType = typeof CLIENT_TYPES[keyof typeof CLIENT_TYPES];\n"],"mappings":"AAqBA,MAAa,EAAkB,CAC7B,oBAAqB,oBACrB,MAAO,QACP,MAAO,QACR,CAsJY,EAAe,CAC1B,OAAQ,SACR,UAAW,YACX,MAAO,QACP,eAAgB,gBAChB,OAAQ,SACR,OAAQ,SACR,OAAQ,SACT"}
1
+ {"version":3,"file":"types.cjs","names":[],"sources":["../../src/health-manager/types.ts"],"sourcesContent":["import type { LoggerInstanceManager } from '@autofleet/logger';\nimport type { Server as HttpServer } from 'node:http';\nimport type { Server as HttpsServer } from 'node:https';\n\nexport type HealthCheckHandler<T> = (options: {\n client: T;\n name: string;\n customHandlersPayload?: any;\n logger: LoggerInstanceManager;\n}) => Promise<void>;\n\nexport type ShutdownHandler<T> = (options: {\n client: T;\n name: string;\n signal?: string;\n customHandlersPayload?: any;\n logger: LoggerInstanceManager;\n}) => Promise<void>;\n\nexport type ShutdownHandlersByStage<T> = Partial<Record<ShutdownStage, ShutdownHandler<T>>>;\n\nexport const SHUTDOWN_STAGES = {\n STOP_ACCEPTING_WORK: 'stopAcceptingWork',\n DRAIN: 'drain',\n CLOSE: 'close',\n} as const;\n\nexport type ShutdownStage = typeof SHUTDOWN_STAGES[keyof typeof SHUTDOWN_STAGES];\n\n/**\n * Configuration for a single client (e.g., rabbit, sequelize, redis, elasticsearch)\n * Allows custom health checks and shutdown logic\n */\nexport interface ClientConfig<T = any, TPayload = any> {\n /** The actual connection instance */\n connection: T;\n\n /** Custom health check function (optional) - will be called during alive/ready checks with client connection and name */\n healthCheck?: HealthCheckHandler<T>;\n\n /**\n * Custom shutdown handlers by stage (optional).\n * Handlers are called during graceful shutdown based on the stages configured in options.enabledShutdownStages.\n * Available stages: stopAcceptingWork (stop new requests), drain (complete in-flight work), close (cleanup resources)\n */\n shutdownHandlers?: ShutdownHandlersByStage<T>;\n /**\n * Additional options specific to the client (optional).\n * If not provided, default values will be used based on the client type.\n */\n options?: {\n /** Whether to include this client in liveness checks (default: true) */\n includeInLivenessCheck?: boolean;\n\n /** Whether to include this client in readiness checks (default: true) */\n includeInReadinessCheck?: boolean;\n\n /** Custom name for this client (used in logging) */\n name?: string;\n\n /** Custom payload to pass to health check and shutdown handlers - use this to pass any additional data your handlers need */\n customHandlersPayload?: TPayload;\n\n /** Which shutdown stages are enabled for this client */\n enabledShutdownStages?: ShutdownStage[];\n };\n}\n\n/** Type alias for server configuration - uses ClientConfig with server instance */\nexport type ServerConfig = ClientConfig<HttpServer | HttpsServer>;\n\n/**\n * General configuration options for the HealthManager\n */\nexport interface HealthManagerConfig {\n /**\n * Delay in milliseconds before shutting down after SIGTERM/SIGINT\n * This gives time for load balancers to stop routing traffic. Should be equal to or greater than readiness probe interval.\n * @default 8000\n */\n shutdownDelayMs?: number;\n\n /**\n * Whether to call process.exit(0) after shutdown sequence completes\n * @default true\n */\n useExit0?: boolean;\n\n /** Whether to auto-setup SIGTERM/SIGINT handlers for graceful shutdown\n * @default true\n */\n shouldSetupSignalHandlers?: boolean;\n\n /**\n * Global shutdown hook called before all clients are shut down\n * @default undefined\n */\n beforeShutdown?: (() => Promise<void>) | undefined;\n\n /**\n * Global shutdown hook called after all clients are shut down\n * @default undefined\n */\n onShutdown?: (() => Promise<void>) | undefined;\n\n /**\n * Enable liveness check optimization - if true and all clients are in both liveness and readiness checks,\n * liveness checks will be skipped when pod is already ready (readiness check passed)\n * @default true\n */\n enableLivenessOptimization?: boolean;\n}\n\n/**\n * List of clients and general configuration for HealthManager\n */\nexport interface HealthManagerOptions {\n /** Client configurations */\n clients?: {\n /** RabbitMQ client configuration - can be a single config or array of configs */\n rabbit?: ClientConfig<any> | ClientConfig<any>[];\n\n /** Sequelize instance configuration - can be a single config or array of configs */\n sequelize?: ClientConfig<any> | ClientConfig<any>[];\n\n /** Redis client configuration - can be a single config or array of configs */\n redis?: ClientConfig<any> | ClientConfig<any>[];\n\n /** Elasticsearch client configuration - can be a single config or array of configs */\n elasticsearch?: ClientConfig<any> | ClientConfig<any>[];\n\n /** Events client configuration - can be a single config or array of configs */\n events?: ClientConfig<any> | ClientConfig<any>[];\n\n /** HTTP/HTTPS server configuration - can be a single config or array of configs */\n server?: ServerConfig | ServerConfig[];\n\n /** Custom client configurations - for any client type not explicitly listed above */\n [key: string]: ClientConfig<any> | ClientConfig<any>[] | undefined;\n };\n\n /** General configuration options */\n config?: HealthManagerConfig;\n\n /** Logger instance for logging messages */\n logger: LoggerInstanceManager;\n}\n\nexport interface RedisClient {\n ping?: () => Promise<string | void>;\n quit?: () => Promise<void>;\n}\n\n/**\n * Sequelize database interface\n */\nexport interface SequelizeClient {\n query?(sql: string | { query: string; values: unknown[]; }): Promise<any>;\n close?: () => Promise<void>;\n}\n\n/**\n * Elasticsearch client interface\n */\nexport interface ElasticsearchClient {\n ping?: () => Promise<boolean>;\n close?: () => Promise<void>;\n}\n\nexport interface EventsClient {\n exitHandler?: (signal?: string) => Promise<void>;\n}\n\n/**\n * RabbitMQ client interface\n */\nexport interface RabbitMQClient {\n isConnected?: () => Promise<boolean> | boolean;\n gracefulShutdown?: (signal?: string) => Promise<void>;\n}\n\nexport const CLIENT_TYPES = {\n RABBIT: 'rabbit',\n SEQUELIZE: 'sequelize',\n REDIS: 'redis',\n ELASTIC_SEARCH: 'elasticsearch',\n EVENTS: 'events',\n SERVER: 'server',\n CUSTOM: 'custom',\n} as const;\n\nexport type ClientType = typeof CLIENT_TYPES[keyof typeof CLIENT_TYPES];\n"],"mappings":"AAqBA,MAAa,EAAkB,CAC7B,oBAAqB,oBACrB,MAAO,QACP,MAAO,QACR,CA4JY,EAAe,CAC1B,OAAQ,SACR,UAAW,YACX,MAAO,QACP,eAAgB,gBAChB,OAAQ,SACR,OAAQ,SACR,OAAQ,SACT"}
@@ -3,20 +3,20 @@ import { Server } from "node:http";
3
3
  import { Server as Server$1 } from "node:https";
4
4
 
5
5
  //#region src/health-manager/types.d.ts
6
- type HealthCheckHandler = (options: {
7
- client: any;
6
+ type HealthCheckHandler<T> = (options: {
7
+ client: T;
8
8
  name: string;
9
9
  customHandlersPayload?: any;
10
10
  logger: LoggerInstanceManager;
11
11
  }) => Promise<void>;
12
- type ShutdownHandler = (options: {
13
- client: any;
12
+ type ShutdownHandler<T> = (options: {
13
+ client: T;
14
14
  name: string;
15
15
  signal?: string;
16
16
  customHandlersPayload?: any;
17
17
  logger: LoggerInstanceManager;
18
18
  }) => Promise<void>;
19
- type ShutdownHandlersByStage = Partial<Record<ShutdownStage, ShutdownHandler>>;
19
+ type ShutdownHandlersByStage<T> = Partial<Record<ShutdownStage, ShutdownHandler<T>>>;
20
20
  declare const SHUTDOWN_STAGES: {
21
21
  readonly STOP_ACCEPTING_WORK: "stopAcceptingWork";
22
22
  readonly DRAIN: "drain";
@@ -31,10 +31,17 @@ interface ClientConfig<T = any, TPayload = any> {
31
31
  /** The actual connection instance */
32
32
  connection: T;
33
33
  /** Custom health check function (optional) - will be called during alive/ready checks with client connection and name */
34
- healthCheck?: HealthCheckHandler;
35
- /** Custom shutdown handlers by stage (optional) - will be called during graceful shutdown at appropriate stages */
36
- shutdownHandlers?: ShutdownHandlersByStage;
37
- /** Additional options specific to the client (optional) */
34
+ healthCheck?: HealthCheckHandler<T>;
35
+ /**
36
+ * Custom shutdown handlers by stage (optional).
37
+ * Handlers are called during graceful shutdown based on the stages configured in options.enabledShutdownStages.
38
+ * Available stages: stopAcceptingWork (stop new requests), drain (complete in-flight work), close (cleanup resources)
39
+ */
40
+ shutdownHandlers?: ShutdownHandlersByStage<T>;
41
+ /**
42
+ * Additional options specific to the client (optional).
43
+ * If not provided, default values will be used based on the client type.
44
+ */
38
45
  options?: {
39
46
  /** Whether to include this client in liveness checks (default: true) */
40
47
  includeInLivenessCheck?: boolean;
@@ -44,8 +51,8 @@ interface ClientConfig<T = any, TPayload = any> {
44
51
  name?: string;
45
52
  /** Custom payload to pass to health check and shutdown handlers - use this to pass any additional data your handlers need */
46
53
  customHandlersPayload?: TPayload;
47
- /** Which shutdown stages this client participates in */
48
- shutdownStages?: ShutdownStage[];
54
+ /** Which shutdown stages are enabled for this client */
55
+ enabledShutdownStages?: ShutdownStage[];
49
56
  };
50
57
  }
51
58
  /** Type alias for server configuration - uses ClientConfig with server instance */
@@ -3,20 +3,20 @@ import { Server } from "node:http";
3
3
  import { Server as Server$1 } from "node:https";
4
4
 
5
5
  //#region src/health-manager/types.d.ts
6
- type HealthCheckHandler = (options: {
7
- client: any;
6
+ type HealthCheckHandler<T> = (options: {
7
+ client: T;
8
8
  name: string;
9
9
  customHandlersPayload?: any;
10
10
  logger: LoggerInstanceManager;
11
11
  }) => Promise<void>;
12
- type ShutdownHandler = (options: {
13
- client: any;
12
+ type ShutdownHandler<T> = (options: {
13
+ client: T;
14
14
  name: string;
15
15
  signal?: string;
16
16
  customHandlersPayload?: any;
17
17
  logger: LoggerInstanceManager;
18
18
  }) => Promise<void>;
19
- type ShutdownHandlersByStage = Partial<Record<ShutdownStage, ShutdownHandler>>;
19
+ type ShutdownHandlersByStage<T> = Partial<Record<ShutdownStage, ShutdownHandler<T>>>;
20
20
  declare const SHUTDOWN_STAGES: {
21
21
  readonly STOP_ACCEPTING_WORK: "stopAcceptingWork";
22
22
  readonly DRAIN: "drain";
@@ -31,10 +31,17 @@ interface ClientConfig<T = any, TPayload = any> {
31
31
  /** The actual connection instance */
32
32
  connection: T;
33
33
  /** Custom health check function (optional) - will be called during alive/ready checks with client connection and name */
34
- healthCheck?: HealthCheckHandler;
35
- /** Custom shutdown handlers by stage (optional) - will be called during graceful shutdown at appropriate stages */
36
- shutdownHandlers?: ShutdownHandlersByStage;
37
- /** Additional options specific to the client (optional) */
34
+ healthCheck?: HealthCheckHandler<T>;
35
+ /**
36
+ * Custom shutdown handlers by stage (optional).
37
+ * Handlers are called during graceful shutdown based on the stages configured in options.enabledShutdownStages.
38
+ * Available stages: stopAcceptingWork (stop new requests), drain (complete in-flight work), close (cleanup resources)
39
+ */
40
+ shutdownHandlers?: ShutdownHandlersByStage<T>;
41
+ /**
42
+ * Additional options specific to the client (optional).
43
+ * If not provided, default values will be used based on the client type.
44
+ */
38
45
  options?: {
39
46
  /** Whether to include this client in liveness checks (default: true) */
40
47
  includeInLivenessCheck?: boolean;
@@ -44,8 +51,8 @@ interface ClientConfig<T = any, TPayload = any> {
44
51
  name?: string;
45
52
  /** Custom payload to pass to health check and shutdown handlers - use this to pass any additional data your handlers need */
46
53
  customHandlersPayload?: TPayload;
47
- /** Which shutdown stages this client participates in */
48
- shutdownStages?: ShutdownStage[];
54
+ /** Which shutdown stages are enabled for this client */
55
+ enabledShutdownStages?: ShutdownStage[];
49
56
  };
50
57
  }
51
58
  /** Type alias for server configuration - uses ClientConfig with server instance */
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","names":[],"sources":["../../src/health-manager/types.ts"],"sourcesContent":["import type { LoggerInstanceManager } from '@autofleet/logger';\nimport type { Server as HttpServer } from 'node:http';\nimport type { Server as HttpsServer } from 'node:https';\n\nexport type HealthCheckHandler = (options: {\n client: any;\n name: string;\n customHandlersPayload?: any;\n logger: LoggerInstanceManager;\n}) => Promise<void>;\n\nexport type ShutdownHandler = (options: {\n client: any;\n name: string;\n signal?: string;\n customHandlersPayload?: any;\n logger: LoggerInstanceManager;\n}) => Promise<void>;\n\nexport type ShutdownHandlersByStage = Partial<Record<ShutdownStage, ShutdownHandler>>;\n\nexport const SHUTDOWN_STAGES = {\n STOP_ACCEPTING_WORK: 'stopAcceptingWork',\n DRAIN: 'drain',\n CLOSE: 'close',\n} as const;\n\nexport type ShutdownStage = typeof SHUTDOWN_STAGES[keyof typeof SHUTDOWN_STAGES];\n\n/**\n * Configuration for a single client (e.g., rabbit, sequelize, redis, elasticsearch)\n * Allows custom health checks and shutdown logic\n */\nexport interface ClientConfig<T = any, TPayload = any> {\n /** The actual connection instance */\n connection: T;\n\n /** Custom health check function (optional) - will be called during alive/ready checks with client connection and name */\n healthCheck?: HealthCheckHandler;\n\n /** Custom shutdown handlers by stage (optional) - will be called during graceful shutdown at appropriate stages */\n shutdownHandlers?: ShutdownHandlersByStage;\n\n /** Additional options specific to the client (optional) */\n options?: {\n /** Whether to include this client in liveness checks (default: true) */\n includeInLivenessCheck?: boolean;\n\n /** Whether to include this client in readiness checks (default: true) */\n includeInReadinessCheck?: boolean;\n\n /** Custom name for this client (used in logging) */\n name?: string;\n\n /** Custom payload to pass to health check and shutdown handlers - use this to pass any additional data your handlers need */\n customHandlersPayload?: TPayload;\n\n /** Which shutdown stages this client participates in */\n shutdownStages?: ShutdownStage[];\n };\n}\n\n/** Type alias for server configuration - uses ClientConfig with server instance */\nexport type ServerConfig = ClientConfig<HttpServer | HttpsServer>;\n\n/**\n * General configuration options for the HealthManager\n */\nexport interface HealthManagerConfig {\n /**\n * Delay in milliseconds before shutting down after SIGTERM/SIGINT\n * This gives time for load balancers to stop routing traffic. Should be equal to or greater than readiness probe interval.\n * @default 8000\n */\n shutdownDelayMs?: number;\n\n /**\n * Whether to call process.exit(0) after shutdown sequence completes\n * @default true\n */\n useExit0?: boolean;\n\n /** Whether to auto-setup SIGTERM/SIGINT handlers for graceful shutdown\n * @default true\n */\n shouldSetupSignalHandlers?: boolean;\n\n /**\n * Global shutdown hook called before all clients are shut down\n * @default undefined\n */\n beforeShutdown?: (() => Promise<void>) | undefined;\n\n /**\n * Global shutdown hook called after all clients are shut down\n * @default undefined\n */\n onShutdown?: (() => Promise<void>) | undefined;\n\n /**\n * Enable liveness check optimization - if true and all clients are in both liveness and readiness checks,\n * liveness checks will be skipped when pod is already ready (readiness check passed)\n * @default true\n */\n enableLivenessOptimization?: boolean;\n}\n\n/**\n * List of clients and general configuration for HealthManager\n */\nexport interface HealthManagerOptions {\n /** Client configurations */\n clients?: {\n /** RabbitMQ client configuration - can be a single config or array of configs */\n rabbit?: ClientConfig<any> | ClientConfig<any>[];\n\n /** Sequelize instance configuration - can be a single config or array of configs */\n sequelize?: ClientConfig<any> | ClientConfig<any>[];\n\n /** Redis client configuration - can be a single config or array of configs */\n redis?: ClientConfig<any> | ClientConfig<any>[];\n\n /** Elasticsearch client configuration - can be a single config or array of configs */\n elasticsearch?: ClientConfig<any> | ClientConfig<any>[];\n\n /** Events client configuration - can be a single config or array of configs */\n events?: ClientConfig<any> | ClientConfig<any>[];\n\n /** HTTP/HTTPS server configuration - can be a single config or array of configs */\n server?: ServerConfig | ServerConfig[];\n\n /** Custom client configurations - for any client type not explicitly listed above */\n [key: string]: ClientConfig<any> | ClientConfig<any>[] | undefined;\n };\n\n /** General configuration options */\n config?: HealthManagerConfig;\n\n /** Logger instance for logging messages */\n logger: LoggerInstanceManager;\n}\n\nexport interface RedisClient {\n ping?: () => Promise<string | void>;\n quit?: () => Promise<void>;\n}\n\n/**\n * Sequelize database interface\n */\nexport interface SequelizeClient {\n query?(sql: string | { query: string; values: unknown[]; }): Promise<any>;\n close?: () => Promise<void>;\n}\n\n/**\n * Elasticsearch client interface\n */\nexport interface ElasticsearchClient {\n ping?: () => Promise<boolean>;\n close?: () => Promise<void>;\n}\n\nexport interface EventsClient {\n exitHandler?: (signal?: string) => Promise<void>;\n}\n\n/**\n * RabbitMQ client interface\n */\nexport interface RabbitMQClient {\n isConnected?: () => Promise<boolean> | boolean;\n gracefulShutdown?: (signal?: string) => Promise<void>;\n}\n\nexport const CLIENT_TYPES = {\n RABBIT: 'rabbit',\n SEQUELIZE: 'sequelize',\n REDIS: 'redis',\n ELASTIC_SEARCH: 'elasticsearch',\n EVENTS: 'events',\n SERVER: 'server',\n CUSTOM: 'custom',\n} as const;\n\nexport type ClientType = typeof CLIENT_TYPES[keyof typeof CLIENT_TYPES];\n"],"mappings":"AAqBA,MAAa,EAAkB,CAC7B,oBAAqB,oBACrB,MAAO,QACP,MAAO,QACR,CAsJY,EAAe,CAC1B,OAAQ,SACR,UAAW,YACX,MAAO,QACP,eAAgB,gBAChB,OAAQ,SACR,OAAQ,SACR,OAAQ,SACT"}
1
+ {"version":3,"file":"types.js","names":[],"sources":["../../src/health-manager/types.ts"],"sourcesContent":["import type { LoggerInstanceManager } from '@autofleet/logger';\nimport type { Server as HttpServer } from 'node:http';\nimport type { Server as HttpsServer } from 'node:https';\n\nexport type HealthCheckHandler<T> = (options: {\n client: T;\n name: string;\n customHandlersPayload?: any;\n logger: LoggerInstanceManager;\n}) => Promise<void>;\n\nexport type ShutdownHandler<T> = (options: {\n client: T;\n name: string;\n signal?: string;\n customHandlersPayload?: any;\n logger: LoggerInstanceManager;\n}) => Promise<void>;\n\nexport type ShutdownHandlersByStage<T> = Partial<Record<ShutdownStage, ShutdownHandler<T>>>;\n\nexport const SHUTDOWN_STAGES = {\n STOP_ACCEPTING_WORK: 'stopAcceptingWork',\n DRAIN: 'drain',\n CLOSE: 'close',\n} as const;\n\nexport type ShutdownStage = typeof SHUTDOWN_STAGES[keyof typeof SHUTDOWN_STAGES];\n\n/**\n * Configuration for a single client (e.g., rabbit, sequelize, redis, elasticsearch)\n * Allows custom health checks and shutdown logic\n */\nexport interface ClientConfig<T = any, TPayload = any> {\n /** The actual connection instance */\n connection: T;\n\n /** Custom health check function (optional) - will be called during alive/ready checks with client connection and name */\n healthCheck?: HealthCheckHandler<T>;\n\n /**\n * Custom shutdown handlers by stage (optional).\n * Handlers are called during graceful shutdown based on the stages configured in options.enabledShutdownStages.\n * Available stages: stopAcceptingWork (stop new requests), drain (complete in-flight work), close (cleanup resources)\n */\n shutdownHandlers?: ShutdownHandlersByStage<T>;\n /**\n * Additional options specific to the client (optional).\n * If not provided, default values will be used based on the client type.\n */\n options?: {\n /** Whether to include this client in liveness checks (default: true) */\n includeInLivenessCheck?: boolean;\n\n /** Whether to include this client in readiness checks (default: true) */\n includeInReadinessCheck?: boolean;\n\n /** Custom name for this client (used in logging) */\n name?: string;\n\n /** Custom payload to pass to health check and shutdown handlers - use this to pass any additional data your handlers need */\n customHandlersPayload?: TPayload;\n\n /** Which shutdown stages are enabled for this client */\n enabledShutdownStages?: ShutdownStage[];\n };\n}\n\n/** Type alias for server configuration - uses ClientConfig with server instance */\nexport type ServerConfig = ClientConfig<HttpServer | HttpsServer>;\n\n/**\n * General configuration options for the HealthManager\n */\nexport interface HealthManagerConfig {\n /**\n * Delay in milliseconds before shutting down after SIGTERM/SIGINT\n * This gives time for load balancers to stop routing traffic. Should be equal to or greater than readiness probe interval.\n * @default 8000\n */\n shutdownDelayMs?: number;\n\n /**\n * Whether to call process.exit(0) after shutdown sequence completes\n * @default true\n */\n useExit0?: boolean;\n\n /** Whether to auto-setup SIGTERM/SIGINT handlers for graceful shutdown\n * @default true\n */\n shouldSetupSignalHandlers?: boolean;\n\n /**\n * Global shutdown hook called before all clients are shut down\n * @default undefined\n */\n beforeShutdown?: (() => Promise<void>) | undefined;\n\n /**\n * Global shutdown hook called after all clients are shut down\n * @default undefined\n */\n onShutdown?: (() => Promise<void>) | undefined;\n\n /**\n * Enable liveness check optimization - if true and all clients are in both liveness and readiness checks,\n * liveness checks will be skipped when pod is already ready (readiness check passed)\n * @default true\n */\n enableLivenessOptimization?: boolean;\n}\n\n/**\n * List of clients and general configuration for HealthManager\n */\nexport interface HealthManagerOptions {\n /** Client configurations */\n clients?: {\n /** RabbitMQ client configuration - can be a single config or array of configs */\n rabbit?: ClientConfig<any> | ClientConfig<any>[];\n\n /** Sequelize instance configuration - can be a single config or array of configs */\n sequelize?: ClientConfig<any> | ClientConfig<any>[];\n\n /** Redis client configuration - can be a single config or array of configs */\n redis?: ClientConfig<any> | ClientConfig<any>[];\n\n /** Elasticsearch client configuration - can be a single config or array of configs */\n elasticsearch?: ClientConfig<any> | ClientConfig<any>[];\n\n /** Events client configuration - can be a single config or array of configs */\n events?: ClientConfig<any> | ClientConfig<any>[];\n\n /** HTTP/HTTPS server configuration - can be a single config or array of configs */\n server?: ServerConfig | ServerConfig[];\n\n /** Custom client configurations - for any client type not explicitly listed above */\n [key: string]: ClientConfig<any> | ClientConfig<any>[] | undefined;\n };\n\n /** General configuration options */\n config?: HealthManagerConfig;\n\n /** Logger instance for logging messages */\n logger: LoggerInstanceManager;\n}\n\nexport interface RedisClient {\n ping?: () => Promise<string | void>;\n quit?: () => Promise<void>;\n}\n\n/**\n * Sequelize database interface\n */\nexport interface SequelizeClient {\n query?(sql: string | { query: string; values: unknown[]; }): Promise<any>;\n close?: () => Promise<void>;\n}\n\n/**\n * Elasticsearch client interface\n */\nexport interface ElasticsearchClient {\n ping?: () => Promise<boolean>;\n close?: () => Promise<void>;\n}\n\nexport interface EventsClient {\n exitHandler?: (signal?: string) => Promise<void>;\n}\n\n/**\n * RabbitMQ client interface\n */\nexport interface RabbitMQClient {\n isConnected?: () => Promise<boolean> | boolean;\n gracefulShutdown?: (signal?: string) => Promise<void>;\n}\n\nexport const CLIENT_TYPES = {\n RABBIT: 'rabbit',\n SEQUELIZE: 'sequelize',\n REDIS: 'redis',\n ELASTIC_SEARCH: 'elasticsearch',\n EVENTS: 'events',\n SERVER: 'server',\n CUSTOM: 'custom',\n} as const;\n\nexport type ClientType = typeof CLIENT_TYPES[keyof typeof CLIENT_TYPES];\n"],"mappings":"AAqBA,MAAa,EAAkB,CAC7B,oBAAqB,oBACrB,MAAO,QACP,MAAO,QACR,CA4JY,EAAe,CAC1B,OAAQ,SACR,UAAW,YACX,MAAO,QACP,eAAgB,gBAChB,OAAQ,SACR,OAAQ,SACR,OAAQ,SACT"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@autofleet/nitur",
3
- "version": "3.0.0-beta.0",
3
+ "version": "3.0.0-beta.1",
4
4
  "description": "A package for service monitoring",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",