Skip to content

Commit

Permalink
Merge pull request #1210 from edenia/dev
Browse files Browse the repository at this point in the history
Production Release
  • Loading branch information
xavier506 committed Jun 13, 2023
2 parents 4cc45cc + b1fd144 commit 23a01f9
Show file tree
Hide file tree
Showing 16 changed files with 142 additions and 49 deletions.
2 changes: 1 addition & 1 deletion hapi/src/services/node.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ const updateNodes = async (nodes = []) => {
}

const updateEndpointInfo = async endpoint => {
if (!endpoint.type || !['api', 'ssl'].includes(endpoint.type)) return
if (!endpoint.type || !['api', 'ssl', 'p2p'].includes(endpoint.type)) return

const updateMutation = `
mutation ($id: uuid, $head_block_time: timestamptz, $response: jsonb, $updated_at: timestamptz,) {
Expand Down
48 changes: 42 additions & 6 deletions hapi/src/services/producer.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,7 @@ const syncProducers = async () => {
await saveEstimateNextUpdate(new Date())
await syncNodes(producers.slice(0, eosConfig.eosTopLimit))
await syncEndpoints()

if (!eosConfig.stateHistoryPluginEndpoint) {
await statsService.sync()
}
await statsService.sync()
}
}

Expand Down Expand Up @@ -145,6 +142,10 @@ const syncNodes = async producers => {
}

const syncEndpoints = async () => {
Promise.all([syncP2PEndpoints(), syncAPIEndpoints()])
}

const syncAPIEndpoints = async () => {
const query = `
{
endpoint_aggregate(where: {type: {_in: ["api", "ssl"]}}) {
Expand Down Expand Up @@ -193,6 +194,40 @@ const syncEndpoints = async () => {
await healthCheckHistoryService.saveHealthRegister(endpoints.flat())
}

const syncP2PEndpoints = async () => {
const query = `
{
endpoint_aggregate(where: {type: {_in: ["p2p"]}}) {
aggregate {
count
}
}
endpoints : endpoint(where: {type: {_in: ["p2p"]}}) {
id
value
type
}
}
`
const {
endpoints,
endpoint_aggregate: {
aggregate: { count }
}
} = await hasuraUtil.request(query)

if (!count) return

await Promise.all(endpoints.map(async endpoint =>{
const result = await producerUtil.isP2PResponding(endpoint.value)

endpoint.response = {...result, isWorking: result.status === 'Success'}
endpoint.updated_at = new Date()

await nodeService.updateEndpointInfo(endpoint)
}))
}

const endpointsHealth = async (endpoints, producerId) => {
const checkedList = []

Expand All @@ -217,7 +252,8 @@ const endpointsHealth = async (endpoints, producerId) => {
endpoint.time = (new Date() - startTime) / 1000
endpoint.response = {
status: response?.status,
statusText: response?.statusText
statusText: response?.statusText,
isWorking: response?.status === StatusCodes.OK
}
endpoint.head_block_time = nodeInfo?.head_block_time || null
endpoint.updated_at = new Date()
Expand All @@ -229,7 +265,7 @@ const endpointsHealth = async (endpoints, producerId) => {
checkedList.push({
...endpoint,
producer_id: producerId,
isWorking: Number(endpoint?.response?.status === StatusCodes.OK)
isWorking: Number(endpoint?.response?.isWorking)
})
}
}
Expand Down
14 changes: 9 additions & 5 deletions hapi/src/utils/eos.util.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,14 @@ const callWithTimeout = async (promise, ms) => {
timeoutID = setTimeout(() => reject(new Error(timeoutMessage)), ms)
})

return Promise.race([promise, timeoutPromise]).then((response) => {
clearTimeout(timeoutID)

return response
})
return Promise.race([promise, timeoutPromise])
.then(response => response)
.catch(error => {
throw error
})
.finally(() => {
clearTimeout(timeoutID)
})
}

const newAccount = async accountName => {
Expand Down Expand Up @@ -259,6 +262,7 @@ const getProducers = async options =>
const getInfo = options => eosApi.getInfo(options || {})

module.exports = {
callWithTimeout,
newAccount,
generateRandomAccountName,
getAccount,
Expand Down
47 changes: 45 additions & 2 deletions hapi/src/utils/producer.util.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,62 @@
const axiosUtil = require('./axios.util')
const eosUtil = require('./eos.util')
const hasuraUtil = require('./hasura.util')
const net = require('node:net')
const os = require('node:os')

const { eosConfig } = require('../config')

const getUrlStatus = async (url, api = '') => {
const urlRegex = /\/$/
url = url.replace(urlRegex, '')

try {
const response = await axiosUtil.instance.get(`${url}${api}`, { timeout: 30000 })
const response = await axiosUtil.instance.get(`${url}${api}`, {
timeout: 30000
})

return response
} catch (error) {
return error.response
}
}

const isP2PResponding = async (endpoint) => {
const splitted = endpoint?.split(':') || {}
const { 0: host, 1: port } = splitted

if (splitted.length !== 2 || !host || !port)
return { status: 'Failed', statusText: 'Invalid endpoint format' }

const isResponding = new Promise((resolve, _) => {
const client = net.createConnection({ host, port }, () => {
client.destroy()
resolve({ status: 'Success', statusText: 'Connection established' })
})

client.on('error', (err) => {
let errorMessage = ''

switch (Math.abs(err?.errno)) {
case os.constants.errno.ECONNREFUSED:
errorMessage = 'Connection refused'
break
case os.constants.errno.ETIMEDOUT:
errorMessage = 'Connection timeout exceeded'
break
default:
errorMessage = 'Connection error'
}

resolve({ status: 'Failed', statusText: errorMessage })
})
})

return eosUtil.callWithTimeout(isResponding, 60000).catch((_) => {
return { status: 'Failed', statusText: 'Connection timeout exceeded' }
})
}

const getNodeInfo = async (url, api = '/v1/chain/get_info') => {
const response = await getUrlStatus(url, api)

Expand All @@ -31,7 +72,8 @@ const getSupportedAPIs = async (api) => {

try {
const response = await axiosUtil.instance.get(
`${api}/v1/node/get_supported_apis`, { timeout: 30000 }
`${api}/v1/node/get_supported_apis`,
{ timeout: 30000 }
)

supportedAPIs = response.data?.apis
Expand Down Expand Up @@ -263,6 +305,7 @@ const jsonParse = (string) => {
}

module.exports = {
isP2PResponding,
getNodeInfo,
getEndpoints,
getExpectedRewards,
Expand Down
1 change: 0 additions & 1 deletion hapi/src/workers/producers.worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ const start = async () => {
}

if (eosConfig.stateHistoryPluginEndpoint) {
run('SYNC STATS INFO', statsService.sync, workersConfig.syncStatsInterval)
run('SYNC BLOCK HISTORY', stateHistoryPluginService.init)
run('SYNC MISSED BLOCKS', missedBlocksService.syncMissedBlocks)
run('SYNC MISSED BLOCKS PER PRODUCER', statsService.getCurrentMissedBlock)
Expand Down
18 changes: 9 additions & 9 deletions webapp/src/components/EndpointsTable/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,13 @@ const EndpointsTable = ({ producers }) => {
const getStatus = endpoint => {
if (endpoint.response.status === undefined) return

if (endpoint.response?.isWorking) {
return !endpoint.head_block_time || isSynchronized(endpoint)
? 'greenLight'
: 'timerOff'
}

switch (Math.floor(endpoint.response?.status / 100)) {
case 2:
return !endpoint.head_block_time || isSynchronized(endpoint)
? 'greenLight'
: 'timerOff'
case 4:
case 5:
return 'yellowLight'
Expand All @@ -77,11 +79,9 @@ const EndpointsTable = ({ producers }) => {
key={`${producer?.name}-${endpointType}-${index}`}
>
{endpoint.value}
{endpointType !== 'p2p' && (
<HealthCheck status={getStatus(endpoint)}>
<HealthCheckInfo healthCheck={endpoint} />
</HealthCheck>
)}
<HealthCheck status={getStatus(endpoint)}>
<HealthCheckInfo healthCheck={endpoint} />
</HealthCheck>
</div>
))
)}
Expand Down
2 changes: 1 addition & 1 deletion webapp/src/components/EndpointsTextList/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const EndpointsTextList = ({ type }) => {
// Gets all responding endpoints
useEffect(() => {
setPagination(prev => ({ ...prev, limit: null }))
handleFilter(type !== 'p2p')
handleFilter(true)
}, [type, handleFilter, setPagination])

useEffect(() => {
Expand Down
2 changes: 1 addition & 1 deletion webapp/src/components/HealthCheck/HealthCheckInfo.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const HealthCheckInfo = ({ healthCheck }) => {
return (
<>
<Typography>
{t('status')}: {healthCheck.response?.status || t('error')}
{t('status')}: {t(healthCheck.response?.status) || t('error')}
</Typography>
<Typography>
{t('response')}: {t(healthCheck.response?.statusText || 'noResponse')}
Expand Down
1 change: 1 addition & 0 deletions webapp/src/components/NoResults/styles.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ export default (theme) => ({
marginBottom: theme.spacing(2),
padding: theme.spacing(2),
alignItems: 'center',
boxShadow: '0px 1px 5px rgba(0, 0, 0, 0.15) !important',
},
})
7 changes: 3 additions & 4 deletions webapp/src/components/NodeCard/EndpointsChips.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,22 +72,21 @@ const EndpointsChips = ({ node }) => {
)
}

const checkedEndpoints = node.endpoints.filter(endpoint => endpoint.type !== 'p2p')
const status = {
totalEndpoints: 0,
failingEndpoints: [],
updatedAt: 'N/A',
isLoading: false
}

for (const endpoint of checkedEndpoints){
for (const endpoint of node.endpoints){
if (endpoint?.response?.status === undefined) {
status.isLoading = true

break
}

if (endpoint?.response?.status !== 200) {
if (!endpoint?.response?.isWorking) {
status.failingEndpoints.push(endpoint.type)
}

Expand All @@ -99,7 +98,7 @@ const EndpointsChips = ({ node }) => {
<>
<dt className={`${classes.bold} ${classes.endpointsTitle}`}>
{t('endpoints')}
{!!checkedEndpoints.length && <EndpointsInfo status={status} />}
{!!node.endpoints.length && <EndpointsInfo status={status} />}
</dt>
<ChipList
list={node.endpoints.map(({ type, value }) => {
Expand Down
2 changes: 1 addition & 1 deletion webapp/src/gql/producer.gql.js
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ export const FASTEST_ENDPOINTS_QUERY = gql`query($today: date){
}`

export const HISTORY_ENDPOINTS_BY_PRODUCER_QUERY = gql`query($id: Int){
endpoints: check_history_by_endpoint(order_by: [{value: asc},{date: asc}], where: {producer_id: {_eq: $id}}) {
endpoints: check_history_by_endpoint(order_by: [{value: asc},{date: asc}], where: {producer_id: {_eq: $id}}, distinct_on: [value]) {
value
date
avg_time
Expand Down
22 changes: 10 additions & 12 deletions webapp/src/hooks/customHooks/useEndpointsState.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,19 +45,17 @@ const useEndpointsState = () => {
}, [data])

const handleFilter = useCallback(value => {
const filter = value
? { response: { _contains: { status: 200 } } }
: { value: { _gt: '' } }
const filter = value
? { response: { _contains: { isWorking: true } } }
: { value: { _gt: '' } }

setPagination(prev => ({
...prev,
page: 1,
where: { ...prev.where, nodes: { endpoints: filter } },
endpointFilter: value
? { _or: [{ type: { _eq: 'p2p' } }, filter] }
: undefined,
}))
}, [setPagination])
setPagination(prev => ({
...prev,
page: 1,
where: { ...prev.where, nodes: { endpoints: filter } },
endpointFilter: value ? filter : undefined,
}))
}, [setPagination])

return [
{ loading, pagination, producers: items, filters },
Expand Down
4 changes: 2 additions & 2 deletions webapp/src/language/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -290,8 +290,8 @@
"cpuBenchmark": "CPU Benchmark Average",
"isFull": "Is full",
"supportedApis": "Supported APIs",
"allWorking": "All API and SSL endpoints are responding",
"noneWorking": "No API or SSL endpoints are responding",
"allWorking": "All endpoints are responding",
"noneWorking": "No endpoints are responding",
"endpointPlural": "Endpoints not responding are the",
"endpointSingular": "Endpoint not responding is the"
},
Expand Down
12 changes: 9 additions & 3 deletions webapp/src/language/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -297,8 +297,8 @@
"cpuBenchmark": "Promedio del Benchmark de CPU",
"isFull": "Es completo",
"supportedApis": "APIs Soportadas",
"allWorking": "Todos los endpoints API y SSL están respondiendo",
"noneWorking": "Ningún endpoint API o SSL está respondiendo",
"allWorking": "Todos los endpoints están respondiendo",
"noneWorking": "Ningún endpoint está respondiendo",
"endpointPlural": "Los endpoints que no responden son los",
"endpointSingular": "El endpoint que no responde es el"
},
Expand Down Expand Up @@ -392,7 +392,13 @@
"Payment Required": "La solicitud requiere un pago",
"Forbidden": "La solicitud está prohibida",
"Request Timeout": "Tiempo de la solicitud superado",
"Too Many Request": "Demasiadas solicitudes"
"Too Many Request": "Demasiadas solicitudes",
"Connection refused": "Conexión rechazada",
"Connection timeout exceeded": "Tiempo de espera de conexión excedido",
"Connection error": "Error de conexión",
"Connection established": "Conexión establecida",
"Success": "Éxitosa",
"Failed": "Fallida"
},
"nodeSearchComponent": {
"title": "Buscar Nodo",
Expand Down
4 changes: 3 additions & 1 deletion webapp/src/routes/EndpointsList/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,9 @@ const EndpointsList = () => {
{!!producers?.length ? (
<EndpointsTable producers={producers} />
) : (
<NoResults />
<div className={classes.noShadow}>
<NoResults />
</div>
)}
{pagination.pages > 1 && (
<div className={classes.pagination}>
Expand Down
5 changes: 5 additions & 0 deletions webapp/src/routes/EndpointsList/styles.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,9 @@ export default (theme) => ({
cardShadow: {
boxShadow: '0px 1px 5px rgba(0, 0, 0, 0.15) !important',
},
noShadow: {
'& .MuiPaper-root': {
boxShadow: 'none !important'
}
}
})

0 comments on commit 23a01f9

Please sign in to comment.