-
Notifications
You must be signed in to change notification settings - Fork 388
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Cria Endpoint /status para lidar com Health Check das dependências do…
… TabNews (#130) * feat: create endpoint that check health for dependencies * refactor: do a simple implementation of the health check, remove unnecessary files
- Loading branch information
Showing
3 changed files
with
138 additions
and
0 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import database from 'infra/database'; | ||
|
||
export default function Health() { | ||
async function getDependencies() { | ||
const dependenciesHandlersToCheck = [ | ||
{ | ||
name: 'database', | ||
handler: checkDatabaseDependency | ||
} | ||
] | ||
|
||
const promises = dependenciesHandlersToCheck.map(async ({ name, handler }) => { | ||
const dependencyResult = await handler() | ||
|
||
return { | ||
name, | ||
result: dependencyResult | ||
} | ||
}) | ||
|
||
const checkedDependencies = await Promise.all(promises); | ||
|
||
// group dependencies by name | ||
return checkedDependencies.reduce((accumulator, currentDependency) => { | ||
accumulator[currentDependency.name] = currentDependency.result | ||
|
||
return accumulator | ||
}, { }) | ||
} | ||
|
||
async function checkDatabaseDependency() { | ||
let result; | ||
try { | ||
const openConnectionsResult = await database.query( | ||
'SELECT sum(numbackends) as opened_connections FROM pg_stat_database' | ||
); | ||
const { opened_connections } = openConnectionsResult.rows[0]; | ||
|
||
result = { | ||
status: 'healthy', | ||
opened_connections: parseInt(opened_connections) | ||
} | ||
} catch (err) { | ||
console.error('database dependency might be down: ', err); | ||
|
||
result = { | ||
status: 'unhealthy' | ||
} | ||
} | ||
|
||
return result; | ||
} | ||
|
||
return { | ||
getDependencies | ||
} | ||
} |
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,42 @@ | ||
import nextConnect from 'next-connect'; | ||
import { formatISO } from 'date-fns'; | ||
import { v4 as uuid } from 'uuid'; | ||
import { NotFoundError, InternalServerError } from 'errors'; | ||
|
||
import healthFactory from 'model/health'; | ||
|
||
const health = healthFactory() | ||
|
||
export default nextConnect({ | ||
attachParams: true, | ||
onNoMatch: onNoMatchHandler, | ||
onError: onErrorHandler, | ||
}) | ||
.use(injectRequestId) | ||
.get(getHandler); | ||
|
||
async function injectRequestId(request, response, next) { | ||
request.id = uuid(); | ||
next(); | ||
} | ||
|
||
async function getHandler(request, response) { | ||
const checkedDependencies = await health.getDependencies(); | ||
|
||
return response.status(200).json({ | ||
updated_at: formatISO(Date.now()), | ||
dependencies: checkedDependencies, | ||
}); | ||
} | ||
|
||
async function onNoMatchHandler(request, response) { | ||
const errorObject = new NotFoundError({ requestId: request.id }); | ||
console.log(errorObject); | ||
return response.status(errorObject.statusCode).json(errorObject); | ||
} | ||
|
||
function onErrorHandler(error, request, response) { | ||
const errorObject = new InternalServerError({ requestId: request.id, stack: error.stack }); | ||
console.error(errorObject); | ||
return response.status(errorObject.statusCode).json(errorObject); | ||
} |
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,39 @@ | ||
import fetch from 'cross-fetch'; | ||
import { version as uuidVersion } from 'uuid'; | ||
import { validate as uuidValidate } from 'uuid'; | ||
import orchestratorFactory from 'tests/orchestrator.js'; | ||
|
||
const orchestrator = orchestratorFactory(); | ||
|
||
beforeAll(async () => { | ||
await orchestrator.waitForAllServices(); | ||
await orchestrator.dropAllTables(); | ||
}); | ||
|
||
describe('[e2e] do a GET request to /api/v1/status', () => { | ||
test('should be able to execute all health-indicators', async () => { | ||
const serverStatusResponse = await fetch(`${orchestrator.webserverUrl}/api/v1/status`); | ||
const serverStatusBody = await serverStatusResponse.json(); | ||
|
||
expect(serverStatusResponse.status).toEqual(200); | ||
expect(serverStatusBody.updated_at).toBeDefined(); | ||
expect(serverStatusBody.dependencies.database).toEqual(expect.objectContaining({ status: 'healthy', opened_connections: 1 })); | ||
}); | ||
}); | ||
|
||
describe('[e2e] do a PUT request to /api/v1/status', () => { | ||
test('should return a 404 response', async () => { | ||
const putStatusResponse = await fetch(`${orchestrator.webserverUrl}/api/v1/status`, { | ||
method: 'put', | ||
}); | ||
const putStatusBody = await putStatusResponse.json(); | ||
|
||
expect(putStatusResponse.status).toEqual(404); | ||
expect(putStatusBody.statusCode).toEqual(404); | ||
expect(putStatusBody.stack).toBeUndefined(); | ||
expect(uuidVersion(putStatusBody.errorId)).toEqual(4); | ||
expect(uuidValidate(putStatusBody.errorId)).toEqual(true); | ||
expect(uuidVersion(putStatusBody.requestId)).toEqual(4); | ||
expect(uuidValidate(putStatusBody.requestId)).toEqual(true); | ||
}); | ||
}); |