Skip to content

Commit

Permalink
feat: add database health checks and remove legacy health check flag
Browse files Browse the repository at this point in the history
Breaking: The config.healthCheck is no longer relevant
  • Loading branch information
thetutlage committed Jun 18, 2024
1 parent 32f377e commit 0373e7f
Show file tree
Hide file tree
Showing 8 changed files with 507 additions and 124 deletions.
60 changes: 30 additions & 30 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
{
"name": "@adonisjs/lucid",
"version": "20.6.0",
"description": "SQL ORM built on top of Active Record pattern",
"version": "20.6.0",
"engines": {
"node": ">=18.16.0"
},
"main": "./build/index.js",
"type": "module",
"files": [
"build/commands",
"build/providers",
Expand All @@ -17,7 +18,6 @@
"build/configure.d.ts",
"build/configure.js"
],
"type": "module",
"exports": {
".": "./build/index.js",
"./schema": "./build/src/schema/main.js",
Expand Down Expand Up @@ -57,25 +57,9 @@
"test": "c8 npm run test:docker",
"index:commands": "adonis-kit index build/commands"
},
"dependencies": {
"@adonisjs/presets": "^2.4.1",
"@faker-js/faker": "^8.4.1",
"@poppinss/hooks": "^7.2.3",
"@poppinss/macroable": "^1.0.2",
"@poppinss/utils": "^6.7.3",
"fast-deep-equal": "^3.1.3",
"igniculus": "^1.5.0",
"kleur": "^4.1.5",
"knex": "^3.1.0",
"knex-dynamic-connection": "^3.1.1",
"pretty-hrtime": "^1.0.3",
"qs": "^6.12.1",
"slash": "^5.1.0",
"tarn": "^3.0.2"
},
"devDependencies": {
"@adonisjs/assembler": "^7.7.0",
"@adonisjs/core": "^6.10.1",
"@adonisjs/core": "^6.11.0",
"@adonisjs/eslint-config": "^1.3.0",
"@adonisjs/prettier-config": "^1.3.0",
"@adonisjs/tsconfig": "^1.3.0",
Expand All @@ -84,15 +68,15 @@
"@japa/assert": "^3.0.0",
"@japa/file-system": "^2.3.0",
"@japa/runner": "^3.1.4",
"@swc/core": "^1.5.27",
"@swc/core": "^1.6.1",
"@types/chance": "^1.1.6",
"@types/luxon": "^3.4.2",
"@types/node": "^20.14.2",
"@types/node": "^20.14.4",
"@types/pretty-hrtime": "^1.0.3",
"@types/qs": "^6.9.15",
"@vinejs/vine": "^2.1.0",
"better-sqlite3": "^11.0.0",
"c8": "^9.1.0",
"c8": "^10.1.2",
"chance": "^1.1.11",
"copyfiles": "^2.4.1",
"cross-env": "^7.0.3",
Expand All @@ -103,16 +87,32 @@
"github-label-sync": "^2.3.1",
"husky": "^9.0.11",
"luxon": "^3.4.4",
"mysql2": "^3.10.0",
"mysql2": "^3.10.1",
"np": "^10.0.5",
"pg": "^8.12.0",
"prettier": "^3.3.1",
"prettier": "^3.3.2",
"reflect-metadata": "^0.2.2",
"sqlite3": "^5.1.7",
"tedious": "^18.2.0",
"ts-node": "^10.9.2",
"typescript": "^5.4.5"
},
"dependencies": {
"@adonisjs/presets": "^2.4.1",
"@faker-js/faker": "^8.4.1",
"@poppinss/hooks": "^7.2.3",
"@poppinss/macroable": "^1.0.2",
"@poppinss/utils": "^6.7.3",
"fast-deep-equal": "^3.1.3",
"igniculus": "^1.5.0",
"kleur": "^4.1.5",
"knex": "^3.1.0",
"knex-dynamic-connection": "^3.2.0",
"pretty-hrtime": "^1.0.3",
"qs": "^6.12.1",
"slash": "^5.1.0",
"tarn": "^3.0.2"
},
"peerDependencies": {
"@adonisjs/assembler": "^7.7.0",
"@adonisjs/core": "^6.10.1",
Expand All @@ -126,8 +126,8 @@
"optional": true
}
},
"license": "MIT",
"author": "virk,adonisjs",
"license": "MIT",
"homepage": "https://github.com/adonisjs/lucid#readme",
"repository": {
"type": "git",
Expand All @@ -140,6 +140,11 @@
"extends": "@adonisjs/eslint-config/package"
},
"prettier": "@adonisjs/prettier-config",
"commitlint": {
"extends": [
"@commitlint/config-conventional"
]
},
"publishConfig": {
"access": "public",
"tag": "latest"
Expand All @@ -150,11 +155,6 @@
"branch": "main",
"anyBranch": false
},
"commitlint": {
"extends": [
"@commitlint/config-conventional"
]
},
"c8": {
"reporter": [
"text",
Expand Down
63 changes: 0 additions & 63 deletions src/connection/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import knex, { Knex } from 'knex'
import { EventEmitter } from 'node:events'
import { patchKnex } from 'knex-dynamic-connection'
import type { Logger } from '@adonisjs/core/logger'
import { HealthCheckResult } from '@adonisjs/core/types/health'
// @ts-expect-error
import { resolveClientNameWithAliases } from 'knex/lib/util/helpers.js'
import { ConnectionConfig, ConnectionContract } from '../types/database.js'
Expand Down Expand Up @@ -256,68 +255,6 @@ export class Connection extends EventEmitter implements ConnectionContract {
patchKnex(this.readClient, this.readConfigResolver.bind(this))
}

/**
* Checks all the read hosts by running a query on them. Stops
* after first error.
*/
private async checkReadHosts() {
const configCopy = Object.assign(
{ log: new ConnectionLogger(this.name, this.logger) },
this.config,
{
debug: false,
}
)
let error: any = null

// eslint-disable-next-line @typescript-eslint/naming-convention
for (let _ of this.readReplicas) {
configCopy.connection = this.readConfigResolver(this.config)
this.logger.trace({ connection: this.name }, 'spawing health check read connection')
const client = knex.knex(configCopy)

try {
if (this.dialectName === 'oracledb') {
await client.raw('SELECT 1 + 1 AS result FROM dual')
} else {
await client.raw('SELECT 1 + 1 AS result')
}
} catch (err) {
error = err
}

/**
* Cleanup client connection
*/
await client.destroy()
this.logger.trace({ connection: this.name }, 'destroying health check read connection')

/**
* Return early when there is an error
*/
if (error) {
break
}
}

return error
}

/**
* Checks for the write host
*/
private async checkWriteHost() {
try {
if (this.dialectName === 'oracledb') {
await this.client!.raw('SELECT 1 + 1 AS result FROM dual')
} else {
await this.client!.raw('SELECT 1 + 1 AS result')
}
} catch (error) {
return error
}
}

/**
* Returns the pool instance for the given connection
*/
Expand Down
71 changes: 71 additions & 0 deletions src/database/checks/db_check.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* @adonisjs/lucid
*
* (c) AdonisJS
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

import { BaseCheck, Result } from '@adonisjs/core/health'
import type { HealthCheckResult } from '@adonisjs/core/types/health'
import type { QueryClientContract } from '../../types/database.js'

/**
* The DbCheck attempts to establish the database connection by
* executing a sample query.
*/
export class DbCheck extends BaseCheck {
#client: QueryClientContract

/**
* Health check public name
*/
name: string

constructor(client: QueryClientContract) {
super()
this.#client = client
this.name = `Database health check (${client.connectionName})`
}

/**
* Returns connection metadata to be shared in the health checks
* report
*/
#getConnectionMetadata() {
return {
connection: {
name: this.#client.connectionName,
dialect: this.#client.dialect.name,
},
}
}

/**
* Internal method to ping the database server
*/
async #ping() {
if (this.#client.dialect.name === 'oracledb') {
await this.#client.rawQuery('SELECT 1 + 1 AS result FROM dual')
} else {
await this.#client!.rawQuery('SELECT 1 + 1 AS result')
}
}

/**
* Executes the health check
*/
async run(): Promise<HealthCheckResult> {
try {
await this.#ping()
return Result.ok('Successfully connected to the database server').mergeMetaData(
this.#getConnectionMetadata()
)
} catch (error) {
return Result.failed(error.message || 'Connection failed', error).mergeMetaData(
this.#getConnectionMetadata()
)
}
}
}
Loading

0 comments on commit 0373e7f

Please sign in to comment.