-
-
Notifications
You must be signed in to change notification settings - Fork 99
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #110 from nestjs/feature/memory-health-indicator
Feature/memory health indicator
- Loading branch information
Showing
19 changed files
with
6,530 additions
and
53 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
import { INestApplication } from '@nestjs/common'; | ||
|
||
import Axios from 'axios'; | ||
import { MemoryHealthIndicator, TerminusModuleOptions } from '../../lib'; | ||
import { bootstrapModule } from '../helper/bootstrap-module'; | ||
|
||
describe('Memory Health', () => { | ||
let app: INestApplication; | ||
let port: number; | ||
|
||
describe('checkRss', () => { | ||
let getTerminusOptions: ( | ||
memory: MemoryHealthIndicator, | ||
) => TerminusModuleOptions; | ||
beforeEach(async () => { | ||
getTerminusOptions = ( | ||
memory: MemoryHealthIndicator, | ||
): TerminusModuleOptions => ({ | ||
endpoints: [ | ||
{ | ||
url: '/health', | ||
healthIndicators: [ | ||
async () => { | ||
const { rss } = process.memoryUsage(); | ||
return memory.checkHeap('memory_rss', rss + 1); | ||
}, | ||
], | ||
}, | ||
], | ||
}); | ||
}); | ||
|
||
it('should check if the rss threshold is not exceeded', async () => { | ||
[app, port] = await bootstrapModule({ | ||
inject: [MemoryHealthIndicator], | ||
useFactory: getTerminusOptions, | ||
}); | ||
const response = await Axios.get(`http://0.0.0.0:${port}/health`); | ||
expect(response.status).toBe(200); | ||
expect(response.data).toEqual({ | ||
status: 'ok', | ||
info: { memory_rss: { status: 'up' } }, | ||
}); | ||
}); | ||
}); | ||
|
||
describe('checkHeap', () => { | ||
it('should check if the heap threshold is not exceeded', async () => { | ||
const getTerminusOptions = ( | ||
memory: MemoryHealthIndicator, | ||
): TerminusModuleOptions => ({ | ||
endpoints: [ | ||
{ | ||
url: '/health', | ||
healthIndicators: [ | ||
async () => | ||
memory.checkHeap('memory_heap', 1 * 1024 * 1024 * 1024 * 1024), | ||
], | ||
}, | ||
], | ||
}); | ||
|
||
[app, port] = await bootstrapModule({ | ||
inject: [MemoryHealthIndicator], | ||
useFactory: getTerminusOptions, | ||
}); | ||
const response = await Axios.get(`http://0.0.0.0:${port}/health`); | ||
expect(response.status).toBe(200); | ||
expect(response.data).toEqual({ | ||
status: 'ok', | ||
info: { memory_heap: { status: 'up' } }, | ||
}); | ||
}); | ||
|
||
it('should check if correctly displays a heap exceeded error', async () => { | ||
[app, port] = await bootstrapModule({ | ||
inject: [MemoryHealthIndicator], | ||
useFactory: (disk: MemoryHealthIndicator): TerminusModuleOptions => ({ | ||
endpoints: [ | ||
{ | ||
url: '/health', | ||
healthIndicators: [async () => disk.checkHeap('memory_heap', 0)], | ||
}, | ||
], | ||
}), | ||
}); | ||
|
||
try { | ||
await Axios.get(`http://0.0.0.0:${port}/health`); | ||
} catch (error) { | ||
expect(error.response.status).toBe(503); | ||
expect(error.response.data).toEqual({ | ||
status: 'error', | ||
error: { | ||
memory_heap: { status: 'down', message: expect.any(String) }, | ||
}, | ||
}); | ||
} | ||
}); | ||
}); | ||
|
||
afterEach(async () => await app.close()); | ||
}); |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
export * from './connection-not-found.error'; | ||
export * from './timeout-error'; | ||
export * from './storage-exceeded.error'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { HealthCheckError } from '@godaddy/terminus'; | ||
import { STORAGE_EXCEEDED } from './messages.constant'; | ||
|
||
/** | ||
* Error which gets thrown when the given storage threshold | ||
* has exceeded. | ||
*/ | ||
export class StorageExceededError extends HealthCheckError { | ||
/** | ||
* Initializes the error | ||
* | ||
* @param {string} keyword The keyword (heap, rss, disk e.g.) | ||
* @param {unknown} cause The cause of the health check error | ||
*/ | ||
constructor(keyword: string, cause: unknown) { | ||
super(STORAGE_EXCEEDED(keyword), cause); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './memory.health'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
import { Injectable } from '@nestjs/common'; | ||
|
||
import { HealthIndicatorResult } from '../../interfaces'; | ||
import { HealthIndicator } from '../health-indicator'; | ||
import { STORAGE_EXCEEDED } from '../../errors/messages.constant'; | ||
import { StorageExceededError } from '../../errors'; | ||
|
||
/** | ||
* The MemoryHealthIndicator contains checks which are related | ||
* to the memory storage of the current running machine | ||
* | ||
* @public | ||
*/ | ||
@Injectable() | ||
export class MemoryHealthIndicator extends HealthIndicator { | ||
/** | ||
* Checks the heap space and returns the status | ||
* | ||
* @param key The key which will be used for the result object | ||
* @param options The options of the `MemoryHealthIndicator` | ||
* | ||
* @throws {StorageExceededError} In case the heap has exceeded the given threshold | ||
* | ||
* @public | ||
* | ||
* @returns {Promise<HealthIndicatorResult>} The result of the health indicator check | ||
* | ||
* @example | ||
* // The process should not use more than 150MB memory | ||
* memoryHealthIndicator.checkRSS('memory_heap', 150 * 1024 * 1024); | ||
*/ | ||
public async checkHeap( | ||
key: string, | ||
heapUsedThreshold: number, | ||
): Promise<HealthIndicatorResult> { | ||
const { heapUsed } = process.memoryUsage(); | ||
|
||
if (heapUsedThreshold < heapUsed) { | ||
throw new StorageExceededError( | ||
'heap', | ||
this.getStatus(key, false, { | ||
message: STORAGE_EXCEEDED('heap'), | ||
}), | ||
); | ||
} | ||
|
||
return this.getStatus(key, true); | ||
} | ||
|
||
/** | ||
* Checks the rss space and returns the status | ||
* | ||
* @param key The key which will be used for the result object | ||
* @param options The options of the `MemoryHealthIndicator` | ||
* | ||
* @throws {StorageExceededError} In case the rss has exceeded the given threshold | ||
* | ||
* @public | ||
* | ||
* @returns {Promise<HealthIndicatorResult>} The result of the health indicator check | ||
* | ||
* @example | ||
* // The process should not have more than 150MB allocated | ||
* memoryHealthIndicator.checkRSS('memory_rss', 150 * 1024 * 1024); | ||
*/ | ||
public async checkRSS( | ||
key: string, | ||
rssThreshold: number, | ||
): Promise<HealthIndicatorResult> { | ||
const { rss } = process.memoryUsage(); | ||
|
||
if (rssThreshold < rss) { | ||
throw new StorageExceededError( | ||
'rss', | ||
this.getStatus(key, false, { | ||
message: STORAGE_EXCEEDED('rss'), | ||
}), | ||
); | ||
} | ||
|
||
return this.getStatus(key, true); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.