Skip to content

Commit

Permalink
feat(Health): roll transactionAnchorRetryInfo into health collection (#…
Browse files Browse the repository at this point in the history
…878)

add a health check on the number of times it takes to get a transaction into the blockchain

References #878, #832
  • Loading branch information
krobi64 authored Dec 7, 2018
1 parent 3224967 commit 5c0ec49
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 3 deletions.
9 changes: 9 additions & 0 deletions src/Health/Health.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { HealthController, HealthControllerConfiguration } from './HealthControl
import { HealthDAO } from './HealthDAO'
import { HealthService, HealthServiceConfiguration } from './HealthService'
import { IPFS, IPFSConfiguration } from './IPFS'
import { IPFSDirectoryHashDAO } from './IPFSDirectoryHashDAO'
import { Router } from './Router'

export interface HealthConfiguration
Expand Down Expand Up @@ -60,6 +61,13 @@ export class Health {
},
})

const ipfsDirectoryHasDAO = new IPFSDirectoryHashDAO({
dependencies: {
ipfsDirectoryHashInfoCollection: this.ipfsDirectoryHashInfoCollection,
},
})
await ipfsDirectoryHasDAO.start()

const bitcoinCore = new BitcoinCore({
host: this.configuration.bitcoinUrl,
port: this.configuration.bitcoinPort,
Expand All @@ -78,6 +86,7 @@ export class Health {
dependencies: {
logger: this.logger,
healthDAO,
ipfsDirectoryHasDAO,
bitcoinCore,
ipfs,
},
Expand Down
32 changes: 32 additions & 0 deletions src/Health/HealthController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { childWithFileName } from 'Helpers/Logging'
import { IPFSHashFailure, ClaimIPFSHashPair } from 'Interfaces'

import { BlockchainInfo, WalletInfo, NetworkInfo, IPFSInfo, EstimatedSmartFeeInfo, HealthDAO } from './HealthDAO'
import { TransactionAnchorRetryInfo, IPFSDirectoryHashDAO } from './IPFSDirectoryHashDAO'

import { IPFS } from './IPFS'

Expand All @@ -15,6 +16,10 @@ enum LogTypes {
error = 'error',
}

export interface HealthError {
readonly error: string
}

export interface HealthControllerConfiguration {
readonly lowWalletBalanceInBitcoin: number
readonly feeEstimateMinTargetBlock: number
Expand All @@ -40,6 +45,7 @@ export const isFailureHard = (failureType: string) => failureType === 'HARD'

export interface Dependencies {
readonly healthDAO: HealthDAO
readonly ipfsDirectoryHasDAO: IPFSDirectoryHashDAO
readonly bitcoinCore: BitcoinCore
readonly logger: Pino.Logger
readonly ipfs: IPFS
Expand All @@ -53,6 +59,7 @@ export interface Arguments {
export class HealthController {
private readonly configuration: HealthControllerConfiguration
private readonly healthDAO: HealthDAO
private readonly ipfsDirectoryHashDAO: IPFSDirectoryHashDAO
private readonly bitcoinCore: BitcoinCore
private readonly logger: Pino.Logger
private readonly ipfs: IPFS
Expand All @@ -61,6 +68,7 @@ export class HealthController {
dependencies: {
logger,
healthDAO,
ipfsDirectoryHasDAO,
bitcoinCore,
ipfs,
},
Expand Down Expand Up @@ -119,6 +127,14 @@ export class HealthController {
return estimatedSmartFeeInfo
}

private async getTransactionAnchorRetryInfo(): Promise<TransactionAnchorRetryInfo | HealthError> {
try {
return await this.ipfsDirectoryHashDAO.getTransactionAnchorRetryInfo()
} catch (e) {
return { error: 'Error retrieving transactionAnchorRetryReport' }
}
}

private async checkIPFSConnection(): Promise<IPFSInfo> {
try {
const ipfsConnection = await this.ipfs.getVersion()
Expand All @@ -134,6 +150,13 @@ export class HealthController {
return ipfsInfo
}

private async updateTransactionAnchorRetryInfo(
transactionAnchorRetryInfo: TransactionAnchorRetryInfo,
): Promise<TransactionAnchorRetryInfo> {
await this.healthDAO.updateTransactionAnchorRetryInfo(transactionAnchorRetryInfo)
return transactionAnchorRetryInfo
}

public async updateIPFSFailures(ipfsHashFailures: ReadonlyArray<IPFSHashFailure>) {
this.logger.debug({ ipfsHashFailures }, 'Updating IPFS Failure Count by failureType')
await ipfsHashFailures.map(
Expand Down Expand Up @@ -185,4 +208,13 @@ export class HealthController {
this.updateIPFSInfo,
this.log(LogTypes.trace)('refreshed IPFS info'),
)

public refreshTransactionAnchorRetryInfo = pipeP(
this.log(LogTypes.trace)('refreshing transaction anchor retry info'),
this.getTransactionAnchorRetryInfo,
this.log(LogTypes.trace)('new info gathered, saving transaction anchor retry info'),
this.updateTransactionAnchorRetryInfo,
this.log(LogTypes.trace)('refreshed transaction anchor retry info'),
)

}
15 changes: 15 additions & 0 deletions src/Health/HealthDAO.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Collection, Db } from 'mongodb'
import { TransactionAnchorRetryInfo } from './IPFSDirectoryHashDAO'

export interface BlockchainInfo {
readonly blocks: number
Expand Down Expand Up @@ -42,6 +43,8 @@ type updateIPFSInfo = (x: IPFSInfo) => Promise<void>

type updateEstimatedSmartFeeInfo = (x: EstimatedSmartFeeInfo) => Promise<void>

type updateTransactionAnchorRetryInfo = (x: TransactionAnchorRetryInfo) => Promise<void>

export interface Dependencies {
readonly db: Db
}
Expand Down Expand Up @@ -121,6 +124,18 @@ export class HealthDAO {
)
}

readonly updateTransactionAnchorRetryInfo: updateTransactionAnchorRetryInfo = async transactionAnchorRetryInfo => {
await this.collection.updateOne(
{ name: 'transactionAnchorRetryInfo' },
{
$set: {
transactionAnchorRetryInfo,
},
},
{ upsert: true },
)
}

readonly increaseHardIPFSFailure = async (): Promise<void> => {
await this.collection.updateOne(
{ name: 'ipfsDownloadRetries' },
Expand Down
3 changes: 2 additions & 1 deletion src/Health/HealthService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Interval } from '@po.et/poet-js'
import * as Pino from 'pino'

import { childWithFileName } from 'Helpers/Logging'
import { secondsToMiliseconds } from 'Helpers/Time'
import { Messaging } from 'Messaging/Messaging'

import { ExchangeConfiguration } from './ExchangeConfiguration'
Expand Down Expand Up @@ -39,7 +40,7 @@ export class HealthService {
this.logger = childWithFileName(logger, __filename)
this.configuration = configuration
this.messaging = messaging
this.interval = new Interval(this.getHealth, this.configuration.healthIntervalInSeconds * 1000)
this.interval = new Interval(this.getHealth, secondsToMiliseconds(this.configuration.healthIntervalInSeconds))
this.exchange = exchange
}

Expand Down
39 changes: 37 additions & 2 deletions src/Health/IPFSDirectoryHashDAO.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Collection } from 'mongodb'
import { isNil } from 'ramda'

export interface UpdateAnchorAttemptInfo {
readonly ipfsDirectoryHash: string
Expand All @@ -7,6 +8,19 @@ export interface UpdateAnchorAttemptInfo {

type updateAnchorAttemptsInfo = (x: UpdateAnchorAttemptInfo) => Promise<void>

export interface AnchorRetryDAOResult {
readonly _id: number
readonly count: number
}

export interface TransactionAnchorRetryEntry {
readonly attempts: number
readonly count: number
}

export type TransactionAnchorRetryInfo = ReadonlyArray<TransactionAnchorRetryEntry>
export type getTransactionAnchorRetryInfo = () => Promise<TransactionAnchorRetryInfo>

export interface Dependencies {
readonly ipfsDirectoryHashInfoCollection: Collection
}
Expand All @@ -26,6 +40,11 @@ export class IPFSDirectoryHashDAO {
this.ipfsDirectoryHashInfoCollection = ipfsDirectoryHashInfoCollection
}

readonly start = async (): Promise<void> => {
await this.ipfsDirectoryHashInfoCollection.createIndex({ ipofsDirectoryHash: 1 }, { unique: true })
await this.ipfsDirectoryHashInfoCollection.createIndex({ txId: 1, attempts: 1 })
}

readonly updateAnchorAttemptsInfo: updateAnchorAttemptsInfo = async anchorAttemptInfo => {
await this.ipfsDirectoryHashInfoCollection.updateOne(
{
Expand All @@ -35,9 +54,25 @@ export class IPFSDirectoryHashDAO {
{
$set: { txId: anchorAttemptInfo.txId },
$inc: { attempts: 1 },
$setOnInsert: { attempts: 1 },
},
{ upsert: true },
)
}
}

readonly getTransactionAnchorRetryInfo: getTransactionAnchorRetryInfo = async () => {
const cursorArray = await this.ipfsDirectoryHashInfoCollection.aggregate([
{ $match: { attempts: { $ne: 1 } } },
{ $group: { _id: '$attempts', count: { $sum: 1} } },
]).toArray()

if (isNil(cursorArray)) return []

return cursorArray.map(
(item: AnchorRetryDAOResult) => (
{
attempts: item._id,
count: item.count,
}
),
)
}}
1 change: 1 addition & 0 deletions src/Health/Router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export class Router {
await this.controller.refreshNetworkInfo()
await this.controller.refreshIPFSInfo()
await this.controller.refreshEstimatedSmartFee()
await this.controller.refreshTransactionAnchorRetryInfo()
} catch (error) {
logger.error({ error }, 'Failed to getHealthInfo')
}
Expand Down

0 comments on commit 5c0ec49

Please sign in to comment.