@adalo/metrics 0.0.0-staging.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.
Files changed (85) hide show
  1. package/.env.example +14 -0
  2. package/.eslintignore +3 -0
  3. package/.eslintrc +61 -0
  4. package/.github/pull_request_template.md +14 -0
  5. package/.github/workflows/code-style.yml +29 -0
  6. package/.github/workflows/deploy-staging.yml +34 -0
  7. package/.github/workflows/deploy.yml +29 -0
  8. package/.github/workflows/tests.yml +17 -0
  9. package/.idea/codeStyles/Project.xml +101 -0
  10. package/.idea/codeStyles/codeStyleConfig.xml +5 -0
  11. package/.idea/git_toolbox_prj.xml +15 -0
  12. package/.idea/inspectionProfiles/Project_Default.xml +6 -0
  13. package/.idea/jsLibraryMappings.xml +6 -0
  14. package/.idea/prettier.xml +6 -0
  15. package/.idea/vcs.xml +6 -0
  16. package/.prettierrc +10 -0
  17. package/README-health.md +234 -0
  18. package/README.md +120 -0
  19. package/__tests__/metricsRedisClient.test.js +138 -0
  20. package/babel.config.js +20 -0
  21. package/lib/health/databaseChecker.d.ts +43 -0
  22. package/lib/health/databaseChecker.d.ts.map +1 -0
  23. package/lib/health/databaseChecker.js +189 -0
  24. package/lib/health/databaseChecker.js.map +1 -0
  25. package/lib/health/healthCheckCache.d.ts +59 -0
  26. package/lib/health/healthCheckCache.d.ts.map +1 -0
  27. package/lib/health/healthCheckCache.js +187 -0
  28. package/lib/health/healthCheckCache.js.map +1 -0
  29. package/lib/health/healthCheckClient.d.ts +124 -0
  30. package/lib/health/healthCheckClient.d.ts.map +1 -0
  31. package/lib/health/healthCheckClient.js +324 -0
  32. package/lib/health/healthCheckClient.js.map +1 -0
  33. package/lib/health/healthCheckUtils.d.ts +52 -0
  34. package/lib/health/healthCheckUtils.d.ts.map +1 -0
  35. package/lib/health/healthCheckUtils.js +129 -0
  36. package/lib/health/healthCheckUtils.js.map +1 -0
  37. package/lib/health/healthCheckWorker.d.ts +2 -0
  38. package/lib/health/healthCheckWorker.d.ts.map +1 -0
  39. package/lib/health/healthCheckWorker.js +70 -0
  40. package/lib/health/healthCheckWorker.js.map +1 -0
  41. package/lib/index.d.ts +10 -0
  42. package/lib/index.d.ts.map +1 -0
  43. package/lib/index.js +105 -0
  44. package/lib/index.js.map +1 -0
  45. package/lib/metrics/baseMetricsClient.d.ts +174 -0
  46. package/lib/metrics/baseMetricsClient.d.ts.map +1 -0
  47. package/lib/metrics/baseMetricsClient.js +428 -0
  48. package/lib/metrics/baseMetricsClient.js.map +1 -0
  49. package/lib/metrics/metricsClient.d.ts +95 -0
  50. package/lib/metrics/metricsClient.d.ts.map +1 -0
  51. package/lib/metrics/metricsClient.js +239 -0
  52. package/lib/metrics/metricsClient.js.map +1 -0
  53. package/lib/metrics/metricsDatabaseClient.d.ts +74 -0
  54. package/lib/metrics/metricsDatabaseClient.d.ts.map +1 -0
  55. package/lib/metrics/metricsDatabaseClient.js +218 -0
  56. package/lib/metrics/metricsDatabaseClient.js.map +1 -0
  57. package/lib/metrics/metricsQueueRedisClient.d.ts +57 -0
  58. package/lib/metrics/metricsQueueRedisClient.d.ts.map +1 -0
  59. package/lib/metrics/metricsQueueRedisClient.js +277 -0
  60. package/lib/metrics/metricsQueueRedisClient.js.map +1 -0
  61. package/lib/metrics/metricsRedisClient.d.ts +71 -0
  62. package/lib/metrics/metricsRedisClient.d.ts.map +1 -0
  63. package/lib/metrics/metricsRedisClient.js +370 -0
  64. package/lib/metrics/metricsRedisClient.js.map +1 -0
  65. package/lib/redisUtils.d.ts +53 -0
  66. package/lib/redisUtils.d.ts.map +1 -0
  67. package/lib/redisUtils.js +140 -0
  68. package/lib/redisUtils.js.map +1 -0
  69. package/package.json +66 -0
  70. package/scripts/README.md +43 -0
  71. package/scripts/clearMetrics.js +6 -0
  72. package/src/health/databaseChecker.js +183 -0
  73. package/src/health/healthCheckCache.js +216 -0
  74. package/src/health/healthCheckClient.js +347 -0
  75. package/src/health/healthCheckUtils.js +125 -0
  76. package/src/health/healthCheckWorker.js +71 -0
  77. package/src/index.ts +9 -0
  78. package/src/metrics/baseMetricsClient.js +494 -0
  79. package/src/metrics/metricsClient.js +284 -0
  80. package/src/metrics/metricsDatabaseClient.js +236 -0
  81. package/src/metrics/metricsQueueRedisClient.js +352 -0
  82. package/src/metrics/metricsRedisClient.js +417 -0
  83. package/src/redisUtils.js +155 -0
  84. package/tsconfig.json +19 -0
  85. package/tsconfig.types.json +11 -0
@@ -0,0 +1,347 @@
1
+ const {
2
+ createDatabasePool,
3
+ runHealthCheck,
4
+ closePool,
5
+ } = require('./databaseChecker')
6
+ const {
7
+ getRedisClientType,
8
+ REDIS_V4,
9
+ IOREDIS,
10
+ REDIS_V3,
11
+ } = require('../redisUtils')
12
+ const { HealthCheckCache } = require('./healthCheckCache')
13
+
14
+ /**
15
+ * @param {string} name
16
+ * @returns {number | undefined}
17
+ */
18
+ function readNumberEnv(name) {
19
+ const raw = process.env[name]
20
+ if (raw == null || raw === '') return undefined
21
+ const num = Number(raw)
22
+ return Number.isFinite(num) ? num : undefined
23
+ }
24
+
25
+ /** @type {{ checkIntervalMs: number, staleThresholdMs: number, checkTimeoutMs: number, maxDbConnectLatencyMs: number }} */
26
+ const DEFAULT_HEALTH_CONFIG = {
27
+ checkIntervalMs: 30_000,
28
+ staleThresholdMs: 180_000,
29
+ checkTimeoutMs: 15_000,
30
+ maxDbConnectLatencyMs:
31
+ readNumberEnv('HEALTH_DB_MAX_CONNECT_LATENCY_MS') ?? 1000,
32
+ }
33
+
34
+ const SENSITIVE_PATTERNS = [
35
+ {
36
+ pattern:
37
+ /(postgres(?:ql)?|mysql|mongodb|redis|amqp):\/\/([^:]+):([^@]+)@([^:/]+)(:\d+)?\/([^\s?]+)/gi,
38
+ replacement: '$1://***:***@***$5/***',
39
+ },
40
+ {
41
+ pattern: /(\w+):\/\/([^:]+):([^@]+)@([^\s/]+)/gi,
42
+ replacement: '$1://***:***@***',
43
+ },
44
+ {
45
+ pattern:
46
+ /(password|passwd|pwd|secret|token|api[_-]?key|auth[_-]?token)["\s]*[:=]["\s]*([^\s,}"]+)/gi,
47
+ replacement: '$1=***',
48
+ },
49
+ {
50
+ pattern:
51
+ /(database|table|schema|role|user|relation|column|index)\s*["']([^"']+)["']/gi,
52
+ replacement: '$1 "***"',
53
+ },
54
+ {
55
+ pattern: /\b(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})(:\d+)?\b/g,
56
+ replacement: '***$2',
57
+ },
58
+ {
59
+ pattern: /\b(host|hostname|server)["\s]*[:=]["\s]*([^\s,}"]+)/gi,
60
+ replacement: '$1=***',
61
+ },
62
+ ]
63
+
64
+ /**
65
+ * @param {string} text
66
+ * @returns {string}
67
+ */
68
+ function maskSensitiveData(text) {
69
+ if (!text || typeof text !== 'string') return text
70
+ let masked = text
71
+ for (const { pattern, replacement } of SENSITIVE_PATTERNS) {
72
+ masked = masked.replace(pattern, replacement)
73
+ }
74
+ return masked
75
+ }
76
+
77
+ /**
78
+ * @typedef {{ env: string, url?: string } | { env: string, client?: any }} HealthResource
79
+ */
80
+ class HealthCheckClient {
81
+ /**
82
+ * @param {Object} options
83
+ * @param {HealthResource[]} options.resources - Must include Redis resource with client
84
+ * @param {Object} [options.config]
85
+ * @param {string} [options.appName] - For cache key: healthcheck:${appName}
86
+ * @param {string} [options.cacheKey] - Redis key (overrides appName)
87
+ */
88
+ constructor(options = {}) {
89
+ this.healthConfig = { ...DEFAULT_HEALTH_CONFIG, ...options.config }
90
+ this.appName =
91
+ options.appName || process.env.BUILD_APP_NAME || 'unknown-app'
92
+
93
+ this.prefixLogs = `[${this.appName}] [HealthCheck]`
94
+
95
+ this._refreshPromise = null
96
+ /** @type {Map<string, { pool: any, type: string }>} */
97
+ this._databasePools = new Map()
98
+
99
+ /** @type {HealthResource[]} */
100
+ this._resources = options.resources || []
101
+
102
+ const redisClient = this._getRedisClientForCache()
103
+ if (redisClient) {
104
+ this._redisClientType = getRedisClientType(redisClient)
105
+ }
106
+
107
+ this._cache = new HealthCheckCache({
108
+ redisClient: redisClient || null,
109
+ cacheKey: options.cacheKey,
110
+ appName: this.appName,
111
+ staleThresholdMs: this.healthConfig.staleThresholdMs,
112
+ })
113
+ }
114
+
115
+ _getEnv(resource) {
116
+ return resource.env ?? resource.name
117
+ }
118
+
119
+ _getRedisClientForCache() {
120
+ const redisResource = this._resources.find(r => 'client' in r && r.client)
121
+ return redisResource?.client || null
122
+ }
123
+
124
+ _getPool(env, url) {
125
+ if (!this._databasePools.has(env)) {
126
+ const { pool, type } = createDatabasePool(
127
+ env,
128
+ url,
129
+ this.healthConfig.checkTimeoutMs
130
+ )
131
+ this._databasePools.set(env, { pool, type })
132
+ }
133
+ return this._databasePools.get(env)
134
+ }
135
+
136
+ async _checkDatabase(resource) {
137
+ const env = this._getEnv(resource)
138
+ const url = 'url' in resource ? resource.url : process.env[env]
139
+ if (!url) {
140
+ return { status: 'error', error: `Env ${env} not set` }
141
+ }
142
+
143
+ try {
144
+ const { pool, type } = this._getPool(env, url)
145
+ const timings = await runHealthCheck(pool, type)
146
+
147
+ const maxConnect = this.healthConfig.maxDbConnectLatencyMs
148
+ if (
149
+ typeof maxConnect === 'number' &&
150
+ Number.isFinite(maxConnect) &&
151
+ timings?.connectMs != null &&
152
+ timings.connectMs > maxConnect
153
+ ) {
154
+ return {
155
+ status: 'error',
156
+ error: `DB connect latency ${timings.connectMs}ms exceeds ${maxConnect}ms`,
157
+ connectMs: timings.connectMs,
158
+ }
159
+ }
160
+
161
+ return { status: 'ok', connectMs: timings.connectMs }
162
+ } catch (err) {
163
+ const timings = err?.healthCheckTimings
164
+ return {
165
+ status: 'error',
166
+ error: maskSensitiveData(err.message),
167
+ ...(timings && typeof timings === 'object'
168
+ ? { connectMs: timings.connectMs }
169
+ : {}),
170
+ }
171
+ }
172
+ }
173
+
174
+ async _checkRedis(resource) {
175
+ const { client } = resource
176
+ if (!client) return { status: 'ok' }
177
+
178
+ try {
179
+ let pong
180
+ if (this._redisClientType === REDIS_V3) {
181
+ pong = await new Promise((resolve, reject) => {
182
+ client.ping((err, result) => {
183
+ if (err) reject(err)
184
+ else resolve(result)
185
+ })
186
+ })
187
+ } else if (
188
+ this._redisClientType === REDIS_V4 ||
189
+ this._redisClientType === IOREDIS
190
+ ) {
191
+ pong = await client.ping()
192
+ } else {
193
+ return { status: 'error', error: 'Unknown Redis client type' }
194
+ }
195
+
196
+ return pong === 'PONG'
197
+ ? { status: 'ok' }
198
+ : { status: 'error', error: `Unexpected: ${pong}` }
199
+ } catch (err) {
200
+ return { status: 'error', error: maskSensitiveData(err.message) }
201
+ }
202
+ }
203
+
204
+ async _performHealthCheckInternal() {
205
+ const resources = {}
206
+
207
+ for (const resource of this._resources) {
208
+ const env = this._getEnv(resource)
209
+
210
+ if ('client' in resource && resource.client) {
211
+ resources[env] = await this._checkRedis(resource)
212
+ } else {
213
+ resources[env] = await this._checkDatabase(resource)
214
+ }
215
+ }
216
+
217
+ const sortedResources = Object.keys(resources)
218
+ .sort()
219
+ .reduce((acc, key) => {
220
+ acc[key] = resources[key]
221
+ return acc
222
+ }, {})
223
+
224
+ const hasError = Object.values(resources).some(r => r.status === 'error')
225
+ const lastCheckAt = Date.now()
226
+
227
+ return {
228
+ status: hasError ? 'error' : 'ok',
229
+ lastCheckAt,
230
+ resources: sortedResources,
231
+ isStale: false,
232
+ config: this.healthConfig,
233
+ }
234
+ }
235
+
236
+ _formatResult(result, cached = false) {
237
+ const isStale =
238
+ !result.lastCheckAt ||
239
+ Date.now() - result.lastCheckAt > this.healthConfig.staleThresholdMs
240
+
241
+ return {
242
+ ...result,
243
+ isStale,
244
+ status: isStale ? 'stale' : result.status,
245
+ ...(isStale && {
246
+ error:
247
+ 'Health check data is stale, health-check worker may not be running. Resource statuses are unknown.',
248
+ }),
249
+ ...(cached && { cached: true }),
250
+ }
251
+ }
252
+
253
+ async performHealthCheck() {
254
+ if (this._refreshPromise) {
255
+ return this._refreshPromise
256
+ }
257
+
258
+ this._refreshPromise = this._performHealthCheckInternal()
259
+ .then(result => {
260
+ this._refreshPromise = null
261
+ return this._formatResult(result)
262
+ })
263
+ .catch(err => {
264
+ this._refreshPromise = null
265
+ throw err
266
+ })
267
+
268
+ return this._refreshPromise
269
+ }
270
+
271
+ async getCachedResult() {
272
+ try {
273
+ const cached = await this._cache.get()
274
+ if (cached) return this._formatResult(cached)
275
+ return null
276
+ } catch (err) {
277
+ console.error(`${this.prefixLogs} Failed to read from cache:`, err)
278
+ return {
279
+ status: 'error',
280
+ lastCheckAt: null,
281
+ resources: {},
282
+ isStale: true,
283
+ error:
284
+ 'Redis unavailable, unable to read health status of other resources',
285
+ config: this.healthConfig,
286
+ }
287
+ }
288
+ }
289
+
290
+ async refreshCache() {
291
+ const result = await this._performHealthCheckInternal()
292
+ await this._cache.set(result)
293
+ return result
294
+ }
295
+
296
+ clearCache() {
297
+ this._refreshPromise = null
298
+ }
299
+
300
+ healthHandler() {
301
+ return async (req, res) => {
302
+ try {
303
+ const result = await this.getCachedResult()
304
+
305
+ if (!result) {
306
+ res.status(503).json({
307
+ status: 'error',
308
+ lastCheckAt: null,
309
+ resources: {},
310
+ isStale: true,
311
+ error:
312
+ 'No health check data yet, health-check worker may not be running',
313
+ config: this.healthConfig,
314
+ })
315
+ return
316
+ }
317
+
318
+ const statusCode = result.status === 'ok' ? 200 : 503
319
+ res.status(statusCode).json(result)
320
+ } catch (err) {
321
+ console.error(`${this.prefixLogs} Health check failed:`, err)
322
+ res.status(503).json({
323
+ status: 'error',
324
+ lastCheckAt: null,
325
+ resources: {},
326
+ isStale: true,
327
+ error:
328
+ 'Redis unavailable, unable to read health status of other resources',
329
+ config: this.healthConfig,
330
+ })
331
+ }
332
+ }
333
+ }
334
+
335
+ async cleanup() {
336
+ for (const [, { pool }] of this._databasePools) {
337
+ try {
338
+ await closePool(pool)
339
+ } catch (err) {
340
+ console.error(`${this.prefixLogs} Error closing database pool:`, err)
341
+ }
342
+ }
343
+ this._databasePools.clear()
344
+ }
345
+ }
346
+
347
+ module.exports = { HealthCheckClient, DEFAULT_HEALTH_CONFIG }
@@ -0,0 +1,125 @@
1
+ const { HealthCheckClient } = require('./healthCheckClient')
2
+
3
+ /**
4
+ * @param {Object<string, string>} urls
5
+ * @returns {{ env: string, url: string }[]}
6
+ */
7
+ function additionalDatabaseUrlsToResources(urls) {
8
+ if (!urls || typeof urls !== 'object') return []
9
+ return Object.entries(urls)
10
+ .filter(([, url]) => url)
11
+ .map(([env, url]) => ({ env, url }))
12
+ }
13
+
14
+ /**
15
+ * @param {Object} options
16
+ * @param {{ env: string } | { env: string, url?: string } | { env: string, client?: any }}[] options.resources
17
+ * @param {string} [options.appName] - For cache key: healthcheck:${appName}
18
+ * @param {string} [options.cacheKey] - Redis key (overrides appName)
19
+ * @param {Object} [options.config]
20
+ * @param {string} [options.databaseUrl]
21
+ * @param {string} [options.databaseName]
22
+ * @param {Object<string, string>} [options.additionalDatabaseUrls]
23
+ * @returns {HealthCheckClient}
24
+ */
25
+ function createHealthCheckWorkerClient(options) {
26
+ const {
27
+ resources,
28
+ appName,
29
+ cacheKey,
30
+ config,
31
+ databaseUrl,
32
+ databaseName,
33
+ additionalDatabaseUrls,
34
+ } = options
35
+
36
+ let resourcesArray = Array.isArray(resources) ? resources : []
37
+
38
+ if (resourcesArray.length === 0) {
39
+ resourcesArray = []
40
+
41
+ if (databaseUrl) {
42
+ const url = databaseUrl || process.env.DATABASE_URL
43
+ if (url) {
44
+ const env = databaseName || 'DATABASE_URL'
45
+ resourcesArray.push({ env, url })
46
+ }
47
+ }
48
+
49
+ const clusterResources = additionalDatabaseUrlsToResources(
50
+ additionalDatabaseUrls || {}
51
+ )
52
+ resourcesArray.push(...clusterResources)
53
+ }
54
+
55
+ const redisResource = resourcesArray.find(r => 'client' in r && r.client)
56
+ if (!redisResource) {
57
+ throw new Error(
58
+ 'resources must include Redis resource with client (e.g. { env: "REDIS_URL", client })'
59
+ )
60
+ }
61
+
62
+ return new HealthCheckClient({
63
+ resources: resourcesArray,
64
+ appName: appName || process.env.BUILD_APP_NAME || 'unknown-app',
65
+ cacheKey,
66
+ config,
67
+ })
68
+ }
69
+
70
+ /**
71
+ * @param {Object} options
72
+ * @param {any} options.redisClient
73
+ * @param {string} [options.appName] - For cache key: healthcheck:${appName}
74
+ * @param {string} [options.cacheKey] - Redis key (e.g. 'health:database:status')
75
+ * @param {Object} [options.config]
76
+ * @returns {HealthCheckClient}
77
+ */
78
+ function createHealthCheckEndpointClient(options) {
79
+ const { redisClient, appName, cacheKey, config } = options
80
+
81
+ if (!redisClient) {
82
+ throw new Error(
83
+ 'redisClient is required for createHealthCheckEndpointClient'
84
+ )
85
+ }
86
+
87
+ return new HealthCheckClient({
88
+ resources: [{ env: 'REDIS_URL', client: redisClient }],
89
+ appName: appName || process.env.BUILD_APP_NAME || 'unknown-app',
90
+ cacheKey,
91
+ config,
92
+ })
93
+ }
94
+
95
+ /**
96
+ * @param {Object} options
97
+ * @param {any} options.redisClient
98
+ * @param {string} [options.cacheKey] - Redis key (e.g. 'health:database:status')
99
+ * @param {string} [options.appName] - For cache key: healthcheck:${appName}
100
+ * @param {Object} [options.config]
101
+ * @returns {(req: any, res: any) => Promise<void>}
102
+ */
103
+ function getHealthCheckStatus(options) {
104
+ const { redisClient, cacheKey, appName, config } = options
105
+
106
+ if (!redisClient) {
107
+ throw new Error('redisClient is required for getHealthCheckStatus')
108
+ }
109
+
110
+ const client = createHealthCheckEndpointClient({
111
+ redisClient,
112
+ cacheKey,
113
+ appName,
114
+ config,
115
+ })
116
+
117
+ return client.healthHandler()
118
+ }
119
+
120
+ module.exports = {
121
+ createHealthCheckWorkerClient,
122
+ createHealthCheckEndpointClient,
123
+ getHealthCheckStatus,
124
+ additionalDatabaseUrlsToResources,
125
+ }
@@ -0,0 +1,71 @@
1
+ /**
2
+ * @param {Object} options
3
+ * @param {{ name: string } | { name: string, url?: string } | { name: string, client: any }}[] options.resources - Must include Redis resource with client
4
+ * @param {string} [options.appName]
5
+ * @param {number} [options.refreshIntervalMs]
6
+ * @param {string} [options.databaseUrl]
7
+ * @param {string} [options.databaseName]
8
+ * @param {Object<string, string>} [options.additionalDatabaseUrls]
9
+ */
10
+ const { createHealthCheckWorkerClient } = require('./healthCheckUtils')
11
+ const { DEFAULT_HEALTH_CONFIG } = require('./healthCheckClient')
12
+
13
+ export function createHealthCheckWorker(options) {
14
+ const {
15
+ refreshIntervalMs = DEFAULT_HEALTH_CONFIG.checkIntervalMs,
16
+ ...workerClientOptions
17
+ } = options
18
+
19
+ const appName =
20
+ workerClientOptions.appName || process.env.BUILD_APP_NAME || 'unknown-app'
21
+ const dynoId = process.env.HOSTNAME || 'unknown-dyno'
22
+ const processType =
23
+ process.env.BUILD_DYNO_PROCESS_TYPE || 'health-check-worker'
24
+ const logValues = process.env.HEALTH_LOG_VALUES === 'true'
25
+ const prefixLogs = `[${processType}] [${appName}] [${dynoId}] [HealthCheck]`
26
+
27
+ const healthCheckClient = createHealthCheckWorkerClient(workerClientOptions)
28
+
29
+ return async function runHealthCheckWorker() {
30
+ console.log(`${prefixLogs} Starting health check worker...`)
31
+ console.log(`${prefixLogs} Refresh interval: ${refreshIntervalMs}ms`)
32
+
33
+ try {
34
+ await healthCheckClient.refreshCache()
35
+ if (logValues) {
36
+ console.log(`${prefixLogs} Initial health check completed`)
37
+ }
38
+ } catch (err) {
39
+ console.error(`${prefixLogs} Initial health check failed:`, err)
40
+ }
41
+
42
+ const interval = setInterval(async () => {
43
+ try {
44
+ const result = await healthCheckClient.refreshCache()
45
+ if (logValues) {
46
+ console.log(
47
+ `${prefixLogs} Health check refreshed at ${result.lastCheckAt}, status: ${result.status}`
48
+ )
49
+ }
50
+ } catch (err) {
51
+ console.error(`${prefixLogs} Health check refresh failed:`, err)
52
+ }
53
+ }, refreshIntervalMs)
54
+
55
+ process.on('SIGTERM', () => {
56
+ console.log(`${prefixLogs} Received SIGTERM, shutting down...`)
57
+ clearInterval(interval)
58
+ healthCheckClient.cleanup().finally(() => {
59
+ process.exit(0)
60
+ })
61
+ })
62
+
63
+ process.on('SIGINT', () => {
64
+ console.log(`${prefixLogs} Received SIGINT, shutting down...`)
65
+ clearInterval(interval)
66
+ healthCheckClient.cleanup().finally(() => {
67
+ process.exit(0)
68
+ })
69
+ })
70
+ }
71
+ }
package/src/index.ts ADDED
@@ -0,0 +1,9 @@
1
+ export * from './metrics/baseMetricsClient'
2
+ export * from './metrics/metricsClient'
3
+ export * from './metrics/metricsRedisClient'
4
+ export * from './metrics/metricsQueueRedisClient'
5
+ export * from './metrics/metricsDatabaseClient'
6
+ export * from './health/healthCheckClient'
7
+ export * from './health/healthCheckUtils'
8
+ export * from './health/healthCheckWorker'
9
+ export * from './redisUtils'