apps/whale-api/src/module.model/_model.probes.ts
import { ProbeIndicator } from '../module.health/probe.indicator'
import { Injectable } from '@nestjs/common'
import { HealthIndicatorResult } from '@nestjs/terminus'
import { Block, BlockMapper } from './block'
import { JsonRpcClient } from '@defichain/jellyfish-api-jsonrpc'
@Injectable()
export class ModelProbeIndicator extends ProbeIndicator {
constructor (
private readonly block: BlockMapper,
private readonly client: JsonRpcClient
) {
super()
}
/**
* Liveness of Model Database
* - unable to get the latest block from BlockMapper
*/
async liveness (): Promise<HealthIndicatorResult> {
try {
await Promise.race([
this.block.getHighest(),
new Promise((resolve, reject) => setTimeout(() => reject(new Error('model.timeout')), 15000))
])
} catch (err) {
return this.withDead('model', 'unable to get the latest block')
}
return this.withAlive('model')
}
/**
* Readiness of Model Database
* - unable to get the latest block
* - synced blocks are undefined
* - synced blocks are more than 2 blocks behind
* - synced latest block height is not more than 90 mins old
*/
async readiness (): Promise<HealthIndicatorResult> {
let highest: Block
let index: number | undefined
let defid: number | undefined
try {
highest = await this.block.getHighest() as Block
index = highest.height
defid = await this.client.blockchain.getBlockCount()
} catch (err) {
return this.withDead('model', 'unable to get the latest block')
}
const details = {
count: {
index: index,
defid: defid
}
}
if (index === undefined || defid === undefined) {
return this.withDead('model', 'synced blocks are undefined', details)
}
if (index + 20 <= defid) {
return this.withDead('model', 'synced blocks are more than 20 blocks behind', details)
}
// index defid can experience rollback, so make sure the condition is only checked if `Model == DeFid`
if (index === defid && secondsSince(highest.time) >= 90 * 60) {
return this.withDead('model', 'defid chain is stale')
}
return this.withAlive('model', details)
}
}
function secondsSince (timeInSeconds: number): number {
return (Math.floor(Date.now() / 1000)) - timeInSeconds
}