Merge pull request #286 from blockworks-foundation/platform-status

consolidate platform status items
This commit is contained in:
saml33 2023-10-10 10:13:12 +11:00 committed by GitHub
commit f8048e5e6f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 222 additions and 105 deletions

View File

@ -1,45 +1,8 @@
import { Connection } from '@solana/web3.js'
import mangoStore from '@store/mangoStore'
import { useEffect, useState } from 'react'
import useInterval from './shared/useInterval'
import { formatNumericValue } from 'utils/numbers' import { formatNumericValue } from 'utils/numbers'
import Tooltip from './shared/Tooltip'
import { useTranslation } from 'react-i18next'
import { StatusDot } from './Tps' import { StatusDot } from './Tps'
import { rpcAlertThreshold, rpcWarningThreshold } from './StatusBar'
const rpcAlertThreshold = 250 const RpcPing = ({ rpcPing }: { rpcPing: number }) => {
const rpcWarningThreshold = 500
const getPingTime = async (
connection: Connection,
setRpcPing: (x: number) => void,
) => {
const startTime = Date.now()
try {
await connection.getSlot()
const endTime = Date.now()
const pingTime = endTime - startTime
setRpcPing(pingTime)
} catch (error) {
console.error('Error pinging the RPC:', error)
return null
}
}
const RpcPing = () => {
const { t } = useTranslation('common')
const connection = mangoStore((s) => s.connection)
const [rpcPing, setRpcPing] = useState(0)
useEffect(() => {
getPingTime(connection, setRpcPing)
}, [])
useInterval(() => {
getPingTime(connection, setRpcPing)
}, 30 * 1000)
return ( return (
<div> <div>
<div className="flex items-center"> <div className="flex items-center">
@ -48,12 +11,10 @@ const RpcPing = () => {
alert={rpcAlertThreshold} alert={rpcAlertThreshold}
warning={rpcWarningThreshold} warning={rpcWarningThreshold}
/> />
<Tooltip content={t('rpc-ping')}> <span className="font-mono text-xs text-th-fgd-2">
<span className="font-mono text-xs text-th-fgd-2"> <span className="mr-1">{formatNumericValue(rpcPing, 0)}</span>
<span className="mr-1">{formatNumericValue(rpcPing, 0)}</span> <span className="font-normal text-th-fgd-4">MS</span>
<span className="font-normal text-th-fgd-4">MS</span> </span>
</span>
</Tooltip>
</div> </div>
</div> </div>
) )

View File

@ -1,15 +1,24 @@
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import Tps from './Tps' import Tps, { StatusDot } from './Tps'
import DiscordIcon from './icons/DiscordIcon' import DiscordIcon from './icons/DiscordIcon'
import { TwitterIcon } from './icons/TwitterIcon' import { TwitterIcon } from './icons/TwitterIcon'
import { DocumentTextIcon } from '@heroicons/react/20/solid' import { DocumentTextIcon } from '@heroicons/react/20/solid'
import { useEffect, useState } from 'react' import { useEffect, useMemo, useState } from 'react'
import { IDL } from '@blockworks-foundation/mango-v4' import { IDL } from '@blockworks-foundation/mango-v4'
import RpcPing from './RpcPing' import RpcPing from './RpcPing'
import Tooltip from './shared/Tooltip' import Tooltip from './shared/Tooltip'
import { useRouter } from 'next/router' import { useRouter } from 'next/router'
import useOffchainServicesHealth from 'hooks/useOffchainServicesHealth'
import mangoStore from '@store/mangoStore'
import { Connection } from '@solana/web3.js'
import { sumBy } from 'lodash'
import useInterval from './shared/useInterval'
const DEFAULT_LATEST_COMMIT = { sha: '', url: '' } const DEFAULT_LATEST_COMMIT = { sha: '', url: '' }
export const tpsAlertThreshold = 1300
export const tpsWarningThreshold = 1000
export const rpcAlertThreshold = 250
export const rpcWarningThreshold = 500
const getLatestCommit = async () => { const getLatestCommit = async () => {
try { try {
@ -32,10 +41,81 @@ const getLatestCommit = async () => {
} }
} }
const getRecentPerformance = async (
connection: Connection,
setTps: (x: number) => void,
) => {
try {
const samples = 2
const response = await connection.getRecentPerformanceSamples(samples)
const totalSecs = sumBy(response, 'samplePeriodSecs')
const totalTransactions = sumBy(response, 'numTransactions')
const tps = totalTransactions / totalSecs
setTps(tps)
} catch {
console.warn('Unable to fetch TPS')
}
}
const getPingTime = async (
connection: Connection,
setRpcPing: (x: number) => void,
) => {
const startTime = Date.now()
try {
await connection.getSlot()
const endTime = Date.now()
const pingTime = endTime - startTime
setRpcPing(pingTime)
} catch (error) {
console.error('Error pinging the RPC:', error)
return null
}
}
const getOverallStatus = (
tps: number,
rpcPing: number,
offchainHealth: number,
) => {
if (tps < tpsWarningThreshold) {
return 'severly-degraded'
} else if (
tps < tpsAlertThreshold ||
rpcPing > rpcWarningThreshold ||
offchainHealth !== 200
) {
return 'degraded'
} else return 'operational'
}
const StatusBar = ({ collapsed }: { collapsed: boolean }) => { const StatusBar = ({ collapsed }: { collapsed: boolean }) => {
const { t } = useTranslation('common') const { t } = useTranslation('common')
const [latestCommit, setLatestCommit] = useState(DEFAULT_LATEST_COMMIT) const [latestCommit, setLatestCommit] = useState(DEFAULT_LATEST_COMMIT)
const router = useRouter() const router = useRouter()
const { offchainHealth, isLoading: loadingOffchainHealth } =
useOffchainServicesHealth()
const connection = mangoStore((s) => s.connection)
const [tps, setTps] = useState(0)
const [rpcPing, setRpcPing] = useState(0)
useEffect(() => {
getPingTime(connection, setRpcPing)
}, [])
useInterval(() => {
getPingTime(connection, setRpcPing)
}, 30 * 1000)
useEffect(() => {
getRecentPerformance(connection, setTps)
}, [])
useInterval(() => {
getRecentPerformance(connection, setTps)
}, 60 * 1000)
useEffect(() => { useEffect(() => {
const { sha } = latestCommit const { sha } = latestCommit
@ -44,16 +124,65 @@ const StatusBar = ({ collapsed }: { collapsed: boolean }) => {
} }
}, [latestCommit]) }, [latestCommit])
const platformHealth = useMemo(() => {
return getOverallStatus(tps, rpcPing, offchainHealth)
}, [tps, rpcPing, offchainHealth])
const dotColor =
platformHealth === 'severly-degraded'
? 'bg-th-error'
: platformHealth === 'degraded'
? 'bg-th-warning'
: 'bg-th-success'
return ( return (
<div <div
className={`fixed hidden ${ className={`fixed hidden ${
collapsed ? 'w-[calc(100vw-64px)]' : 'w-[calc(100vw-200px)]' collapsed ? 'w-[calc(100vw-64px)]' : 'w-[calc(100vw-200px)]'
} bottom-0 z-10 bg-th-input-bkg px-4 py-1 md:grid md:grid-cols-3 md:px-6`} } bottom-0 z-10 bg-th-input-bkg px-4 py-1 md:grid md:grid-cols-3 md:px-6`}
> >
<div className="col-span-1 flex items-center space-x-2"> <div className="col-span-1 flex items-center">
<Tps /> <Tooltip
<span className="text-th-fgd-4">|</span> content={
<RpcPing /> <div className="space-y-2">
<div>
<p className="mb-0.5">{t('solana-tps')}</p>
<Tps tps={tps} />
</div>
<div>
<p className="mb-0.5">{t('rpc-ping')}</p>
<RpcPing rpcPing={rpcPing} />
</div>
{!loadingOffchainHealth ? (
<div className="flex items-center">
<StatusDot
status={offchainHealth}
alert={201}
warning={301}
/>
<span className="text-xs text-th-fgd-2">
{t('offchain-services')}
</span>
</div>
) : null}
</div>
}
placement="top-start"
>
<div className="flex items-center">
<div className="relative mr-1 h-3 w-3">
<div
className={`absolute left-0.5 top-0.5 h-2 w-2 rounded-full ${dotColor}`}
/>
<div
className={`absolute h-3 w-3 rounded-full opacity-40 ${dotColor}`}
/>
</div>
<p className="tooltip-underline text-xs leading-none">
{t(platformHealth)}
</p>
</div>
</Tooltip>
</div> </div>
<div className="col-span-1 flex items-center justify-center"> <div className="col-span-1 flex items-center justify-center">
<Tooltip content={t('program-version')}> <Tooltip content={t('program-version')}>

View File

@ -1,45 +1,8 @@
import { useEffect, useState } from 'react' import { CLUSTER } from '@store/mangoStore'
import sumBy from 'lodash/sumBy'
import { Connection } from '@solana/web3.js'
import mangoStore, { CLUSTER } from '@store/mangoStore'
import useInterval from './shared/useInterval'
import { formatNumericValue } from 'utils/numbers' import { formatNumericValue } from 'utils/numbers'
import Tooltip from './shared/Tooltip' import { tpsAlertThreshold, tpsWarningThreshold } from './StatusBar'
import { useTranslation } from 'react-i18next'
const tpsAlertThreshold = 1000
const tpsWarningThreshold = 1300
const getRecentPerformance = async (
connection: Connection,
setTps: (x: number) => void,
) => {
try {
const samples = 2
const response = await connection.getRecentPerformanceSamples(samples)
const totalSecs = sumBy(response, 'samplePeriodSecs')
const totalTransactions = sumBy(response, 'numTransactions')
const tps = totalTransactions / totalSecs
setTps(tps)
} catch {
console.warn('Unable to fetch TPS')
}
}
const Tps = () => {
const { t } = useTranslation('common')
const connection = mangoStore((s) => s.connection)
const [tps, setTps] = useState(0)
useEffect(() => {
getRecentPerformance(connection, setTps)
}, [])
useInterval(() => {
getRecentPerformance(connection, setTps)
}, 60 * 1000)
const Tps = ({ tps }: { tps: number }) => {
if (CLUSTER == 'mainnet-beta') { if (CLUSTER == 'mainnet-beta') {
return ( return (
<div> <div>
@ -50,12 +13,9 @@ const Tps = () => {
warning={tpsWarningThreshold} warning={tpsWarningThreshold}
isLessThan isLessThan
/> />
<Tooltip content={t('solana-tps-desc')}> <span className="font-mono text-xs text-th-fgd-2">
<span className="font-mono text-xs text-th-fgd-2"> {formatNumericValue(tps, 0)}
<span className="mr-1">{formatNumericValue(tps, 0)}</span> </span>
<span className="font-normal text-th-fgd-4">TPS</span>
</span>
</Tooltip>
</div> </div>
</div> </div>
) )

View File

@ -0,0 +1,52 @@
import useInterval from '@components/shared/useInterval'
import { useQuery } from '@tanstack/react-query'
import { useMemo } from 'react'
const fetchOffchainHealth = async () => {
try {
const [dbHealthResponse, redisHealthResponse, serverHealthResponse] =
await Promise.all([
fetch('https://api.mngo.cloud/data/health/db'),
fetch('https://api.mngo.cloud/data/health/redis'),
fetch('https://api.mngo.cloud/data/health/server'),
])
const [dbHealth, redisHealth, serverHealth] = await Promise.all([
dbHealthResponse.json(),
redisHealthResponse.json(),
serverHealthResponse.json(),
])
return { dbHealth, redisHealth, serverHealth }
} catch (e) {
console.log('Failed to check offchain services health', e)
return { dbHealth: 500, redisHealth: 500, serverHealth: 500 }
}
}
export default function useOffchainServicesHealth() {
const {
data: offchainHealthData,
isLoading,
refetch,
} = useQuery(['offchain-health'], () => fetchOffchainHealth(), {
cacheTime: 1000 * 60 * 10,
staleTime: 1000 * 60,
retry: 3,
})
useInterval(() => {
refetch()
}, 60 * 1000)
const offchainHealth = useMemo(() => {
if (!offchainHealthData) return 500
const somethingWrong = Object.values(offchainHealthData).filter(
(v) => v !== 200,
)
if (!somethingWrong.length) {
return 200
} else if (somethingWrong.length < 3) {
return 300
} else return 500
}, [offchainHealthData])
return { offchainHealth, isLoading }
}

View File

@ -58,6 +58,7 @@
"date": "Date", "date": "Date",
"date-from": "Date From", "date-from": "Date From",
"date-to": "Date To", "date-to": "Date To",
"degraded": "Degraded",
"delegate": "Delegate", "delegate": "Delegate",
"delegate-account": "Delegate Account", "delegate-account": "Delegate Account",
"delegate-account-info": "Account delegated to: {{delegate}}", "delegate-account-info": "Account delegated to: {{delegate}}",
@ -121,6 +122,8 @@
"new-account-success": "Your new account is ready 😎", "new-account-success": "Your new account is ready 😎",
"new-version": "New version available", "new-version": "New version available",
"no": "No", "no": "No",
"offchain-services": "Offchain Services",
"operational": "Operational",
"optional": "Optional", "optional": "Optional",
"outstanding-balance": "Outstanding Balance", "outstanding-balance": "Outstanding Balance",
"overview": "Overview", "overview": "Overview",
@ -142,7 +145,7 @@
"risks": "Risks", "risks": "Risks",
"rolling-change": "24h Change", "rolling-change": "24h Change",
"route": "Route", "route": "Route",
"rpc-ping": "Ping time with the RPC node", "rpc-ping": "RPC Ping",
"save": "Save", "save": "Save",
"select": "Select", "select": "Select",
"select-borrow-token": "Select Borrow Token", "select-borrow-token": "Select Borrow Token",
@ -152,9 +155,9 @@
"select-withdraw-token": "Select Withdraw Token", "select-withdraw-token": "Select Withdraw Token",
"sell": "Sell", "sell": "Sell",
"settings": "Settings", "settings": "Settings",
"severly-degraded": "Severly Degraded",
"show-more": "Show More", "show-more": "Show More",
"solana-tps": "Solana TPS", "solana-tps": "Solana TPS",
"solana-tps-desc": "Solana Network transactions per second",
"soon": "Soon", "soon": "Soon",
"spot": "Spot", "spot": "Spot",
"spot-markets": "Spot Markets", "spot-markets": "Spot Markets",

View File

@ -58,6 +58,7 @@
"date": "Date", "date": "Date",
"date-from": "Date From", "date-from": "Date From",
"date-to": "Date To", "date-to": "Date To",
"degraded": "Degraded",
"delegate": "Delegate", "delegate": "Delegate",
"delegate-account": "Delegate Account", "delegate-account": "Delegate Account",
"delegate-account-info": "Account delegated to: {{delegate}}", "delegate-account-info": "Account delegated to: {{delegate}}",
@ -121,6 +122,8 @@
"new-account-success": "Your new account is ready 😎", "new-account-success": "Your new account is ready 😎",
"new-version": "New version available", "new-version": "New version available",
"no": "No", "no": "No",
"offchain-services": "Offchain Services",
"operational": "Operational",
"optional": "Optional", "optional": "Optional",
"outstanding-balance": "Outstanding Balance", "outstanding-balance": "Outstanding Balance",
"overview": "Overview", "overview": "Overview",
@ -142,7 +145,7 @@
"risks": "Risks", "risks": "Risks",
"rolling-change": "24h Change", "rolling-change": "24h Change",
"route": "Route", "route": "Route",
"rpc-ping": "Ping time with the RPC node", "rpc-ping": "RPC Ping",
"save": "Save", "save": "Save",
"select": "Select", "select": "Select",
"select-borrow-token": "Select Borrow Token", "select-borrow-token": "Select Borrow Token",
@ -152,9 +155,9 @@
"select-withdraw-token": "Select Withdraw Token", "select-withdraw-token": "Select Withdraw Token",
"sell": "Sell", "sell": "Sell",
"settings": "Settings", "settings": "Settings",
"severly-degraded": "Severly Degraded",
"show-more": "Show More", "show-more": "Show More",
"solana-tps": "Solana TPS", "solana-tps": "Solana TPS",
"solana-tps-desc": "Solana Network transactions per second",
"soon": "Soon", "soon": "Soon",
"spot": "Spot", "spot": "Spot",
"spot-markets": "Spot Markets", "spot-markets": "Spot Markets",

View File

@ -58,6 +58,7 @@
"date": "Date", "date": "Date",
"date-from": "Date From", "date-from": "Date From",
"date-to": "Date To", "date-to": "Date To",
"degraded": "Degraded",
"delegate": "Delegate", "delegate": "Delegate",
"delegate-account": "Delegate Account", "delegate-account": "Delegate Account",
"delegate-account-info": "Account delegated to: {{delegate}}", "delegate-account-info": "Account delegated to: {{delegate}}",
@ -121,6 +122,8 @@
"new-account-success": "Your new account is ready 😎", "new-account-success": "Your new account is ready 😎",
"new-version": "New version available", "new-version": "New version available",
"no": "No", "no": "No",
"offchain-services": "Offchain Services",
"operational": "Operational",
"optional": "Optional", "optional": "Optional",
"outstanding-balance": "Outstanding Balance", "outstanding-balance": "Outstanding Balance",
"overview": "Overview", "overview": "Overview",
@ -142,7 +145,7 @@
"risks": "Risks", "risks": "Risks",
"rolling-change": "24h Change", "rolling-change": "24h Change",
"route": "Route", "route": "Route",
"rpc-ping": "Ping time with the RPC node", "rpc-ping": "RPC Ping",
"save": "Save", "save": "Save",
"select": "Select", "select": "Select",
"select-borrow-token": "Select Borrow Token", "select-borrow-token": "Select Borrow Token",
@ -152,9 +155,9 @@
"select-withdraw-token": "Select Withdraw Token", "select-withdraw-token": "Select Withdraw Token",
"sell": "Sell", "sell": "Sell",
"settings": "Settings", "settings": "Settings",
"severly-degraded": "Severly Degraded",
"show-more": "Show More", "show-more": "Show More",
"solana-tps": "Solana TPS", "solana-tps": "Solana TPS",
"solana-tps-desc": "Solana Network transactions per second",
"soon": "Soon", "soon": "Soon",
"spot": "Spot", "spot": "Spot",
"spot-markets": "Spot Markets", "spot-markets": "Spot Markets",

View File

@ -58,6 +58,7 @@
"date": "日期", "date": "日期",
"date-from": "从", "date-from": "从",
"date-to": "至", "date-to": "至",
"degraded": "Degraded",
"delegate": "委托", "delegate": "委托",
"delegate-account": "委托帐户", "delegate-account": "委托帐户",
"delegate-account-info": "帐户委托给: {{delegate}}", "delegate-account-info": "帐户委托给: {{delegate}}",
@ -120,7 +121,9 @@
"new-account-success": "您的新帐户准备好了😎", "new-account-success": "您的新帐户准备好了😎",
"new-version": "新版本出来了", "new-version": "新版本出来了",
"no": "不", "no": "不",
"offchain-services": "Offchain Services",
"optional": "可选", "optional": "可选",
"operational": "Operational",
"outstanding-balance": "未结余额", "outstanding-balance": "未结余额",
"overview": "摘要", "overview": "摘要",
"perp": "合约", "perp": "合约",
@ -151,9 +154,9 @@
"select-withdraw-token": "选提出币种", "select-withdraw-token": "选提出币种",
"sell": "卖", "sell": "卖",
"settings": "设置", "settings": "设置",
"severly-degraded": "Severly Degraded",
"show-more": "显示更多", "show-more": "显示更多",
"solana-tps": "Solana TPS", "solana-tps": "Solana TPS",
"solana-tps-desc": "Solana网络每秒的交易量",
"soon": "等一下", "soon": "等一下",
"spot": "现货", "spot": "现货",
"spot-markets": "现货市场", "spot-markets": "现货市场",

View File

@ -58,6 +58,7 @@
"date": "日期", "date": "日期",
"date-from": "從", "date-from": "從",
"date-to": "至", "date-to": "至",
"degraded": "Degraded",
"delegate": "委託", "delegate": "委託",
"delegate-account": "委託帳戶", "delegate-account": "委託帳戶",
"delegate-account-info": "帳戶委託給: {{delegate}}", "delegate-account-info": "帳戶委託給: {{delegate}}",
@ -120,6 +121,8 @@
"new-account-success": "您的新帳戶準備好了😎", "new-account-success": "您的新帳戶準備好了😎",
"new-version": "新版本出來了", "new-version": "新版本出來了",
"no": "不", "no": "不",
"offchain-services": "Offchain Services",
"operational": "Operational",
"optional": "可選", "optional": "可選",
"outstanding-balance": "未結餘額", "outstanding-balance": "未結餘額",
"overview": "摘要", "overview": "摘要",
@ -151,9 +154,9 @@
"select-withdraw-token": "選提出幣種", "select-withdraw-token": "選提出幣種",
"sell": "賣", "sell": "賣",
"settings": "設置", "settings": "設置",
"severly-degraded": "Severly Degraded",
"show-more": "顯示更多", "show-more": "顯示更多",
"solana-tps": "Solana TPS", "solana-tps": "Solana TPS",
"solana-tps-desc": "Solana網絡每秒的交易量",
"soon": "等一下", "soon": "等一下",
"spot": "現貨", "spot": "現貨",
"spot-markets": "現貨市場", "spot-markets": "現貨市場",