mirror of
https://github.com/IT4Change/gradido.git
synced 2026-03-01 12:44:43 +00:00
make restart and exit GradidoNode Process more robust, fix error in ensureCommunitiesAvailable
This commit is contained in:
parent
f66f33307d
commit
94ce58a68f
@ -3,11 +3,13 @@ import { getLogger, Logger } from 'log4js'
|
||||
import { CONFIG } from '../../config'
|
||||
import {
|
||||
GRADIDO_NODE_KILL_TIMEOUT_MILLISECONDS,
|
||||
GRADIDO_NODE_MIN_RUNTIME_BEFORE_EXIT_MILLISECONDS,
|
||||
GRADIDO_NODE_MIN_RUNTIME_BEFORE_RESTART_MILLISECONDS,
|
||||
GRADIDO_NODE_RUNTIME_PATH,
|
||||
LOG4JS_BASE_CATEGORY,
|
||||
} from '../../config/const'
|
||||
|
||||
import { Mutex } from 'async-mutex'
|
||||
import { delay } from '../../utils/time'
|
||||
/**
|
||||
* A Singleton class defines the `getInstance` method that lets clients access
|
||||
* the unique singleton instance.
|
||||
@ -22,6 +24,7 @@ export class GradidoNodeProcess {
|
||||
private logger: Logger
|
||||
private lastStarted: Date | null = null
|
||||
private exitCalled: boolean = false
|
||||
private restartMutex: Mutex = new Mutex()
|
||||
|
||||
private constructor() {
|
||||
// constructor is private to prevent instantiation from outside
|
||||
@ -55,7 +58,7 @@ export class GradidoNodeProcess {
|
||||
USERPROFILE: CONFIG.DLT_GRADIDO_NODE_SERVER_HOME_FOLDER,
|
||||
HOME: CONFIG.DLT_GRADIDO_NODE_SERVER_HOME_FOLDER,
|
||||
},
|
||||
onExit(proc, exitCode, signalCode, error) {
|
||||
onExit(_proc, exitCode, signalCode, error) {
|
||||
logger.warn(`GradidoNodeProcess exited with code ${exitCode} and signalCode ${signalCode}`)
|
||||
if (error) {
|
||||
logger.error(`GradidoNodeProcess exit error: ${error}`)
|
||||
@ -69,7 +72,6 @@ export class GradidoNodeProcess {
|
||||
})
|
||||
}*/
|
||||
}
|
||||
logger.debug(`ressource usage: ${JSON.stringify(proc?.resourceUsage(), null, 2)}`)
|
||||
const gradidoNodeProcess = GradidoNodeProcess.getInstance()
|
||||
gradidoNodeProcess.proc = null
|
||||
if (
|
||||
@ -90,11 +92,16 @@ export class GradidoNodeProcess {
|
||||
}
|
||||
|
||||
public async restart() {
|
||||
const release = await this.restartMutex.acquire()
|
||||
try {
|
||||
if (this.proc) {
|
||||
await this.exit()
|
||||
this.exitCalled = false
|
||||
this.start()
|
||||
}
|
||||
} finally {
|
||||
release()
|
||||
}
|
||||
}
|
||||
|
||||
public getLastStarted(): Date | null {
|
||||
@ -104,6 +111,9 @@ export class GradidoNodeProcess {
|
||||
public async exit(): Promise<void> {
|
||||
this.exitCalled = true
|
||||
if (this.proc) {
|
||||
if (this.lastStarted && Date.now() - this.lastStarted.getTime() < GRADIDO_NODE_MIN_RUNTIME_BEFORE_EXIT_MILLISECONDS) {
|
||||
await delay(GRADIDO_NODE_MIN_RUNTIME_BEFORE_EXIT_MILLISECONDS - Date.now() - this.lastStarted.getTime())
|
||||
}
|
||||
this.proc.kill('SIGTERM')
|
||||
const timeout = setTimeout(() => {
|
||||
this.logger.warn(
|
||||
|
||||
@ -27,7 +27,8 @@ export async function ensureCommunitiesAvailable(communityTopicIds: HieroId[]):
|
||||
CONFIG.DLT_GRADIDO_NODE_SERVER_HOME_FOLDER,
|
||||
GRADIDO_NODE_HOME_FOLDER_NAME,
|
||||
)
|
||||
if (!checkCommunityAvailable(communityTopicIds, homeFolder)) {
|
||||
const communityTopicIdsSet = new Set(communityTopicIds)
|
||||
if (!checkCommunityAvailable(communityTopicIdsSet, homeFolder)) {
|
||||
await exportCommunities(homeFolder, BackendClient.getInstance())
|
||||
return GradidoNodeProcess.getInstance().restart()
|
||||
}
|
||||
@ -65,7 +66,7 @@ export async function exportCommunities(homeFolder: string, client: BackendClien
|
||||
logger.info(`exported ${communitiesForDltNodeServer.length} communities to ${communitiesPath}`)
|
||||
}
|
||||
|
||||
export function checkCommunityAvailable(communityTopicIds: HieroId[], homeFolder: string): boolean {
|
||||
export function checkCommunityAvailable(communityTopicIds: Set<HieroId>, homeFolder: string): boolean {
|
||||
const communitiesPath = path.join(homeFolder, 'communities.json')
|
||||
if (!checkFileExist(communitiesPath)) {
|
||||
return false
|
||||
@ -73,12 +74,13 @@ export function checkCommunityAvailable(communityTopicIds: HieroId[], homeFolder
|
||||
const communities = JSON.parse(fs.readFileSync(communitiesPath, 'utf-8'))
|
||||
let foundCount = 0
|
||||
for (const community of communities) {
|
||||
if (communityTopicIds.includes(community.hieroTopicId)) {
|
||||
if (communityTopicIds.has(community.hieroTopicId)) {
|
||||
foundCount++
|
||||
if (foundCount >= communityTopicIds.length) {
|
||||
if (foundCount >= communityTopicIds.size) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
logger.debug(`community not found for topic ids: ${communityTopicIds}, communities: ${JSON.stringify(communities, null, 2)}`)
|
||||
return false
|
||||
}
|
||||
|
||||
@ -15,7 +15,7 @@ import {
|
||||
TransactionId,
|
||||
Wallet,
|
||||
} from '@hashgraph/sdk'
|
||||
import { GradidoTransaction } from 'gradido-blockchain-js'
|
||||
import { GradidoTransaction, Profiler } from 'gradido-blockchain-js'
|
||||
import { getLogger, Logger } from 'log4js'
|
||||
import * as v from 'valibot'
|
||||
import { CONFIG } from '../../config'
|
||||
@ -24,8 +24,7 @@ import { HieroId, hieroIdSchema } from '../../schemas/typeGuard.schema'
|
||||
import { type TopicInfoOutput, topicInfoSchema } from './output.schema'
|
||||
import { GradidoNodeClient } from '../GradidoNode/GradidoNodeClient'
|
||||
import { GradidoNodeProcess } from '../GradidoNode/GradidoNodeProcess'
|
||||
import { printTimeDuration } from '../../utils/time'
|
||||
|
||||
import { durationInMinutesFromDates, printTimeDuration } from '../../utils/time'
|
||||
// https://docs.hedera.com/hedera/sdks-and-apis/hedera-api/consensus/consensusupdatetopic
|
||||
export const MIN_AUTORENEW_PERIOD = 6999999 //seconds
|
||||
export const MAX_AUTORENEW_PERIOD = 8000001 // seconds
|
||||
@ -75,7 +74,7 @@ export class HieroClient {
|
||||
topicId: HieroId,
|
||||
transaction: GradidoTransaction,
|
||||
): Promise<TransactionId | null> {
|
||||
const startTime = new Date()
|
||||
const timeUsed = new Profiler()
|
||||
this.transactionInternNr++
|
||||
const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.client.HieroClient`)
|
||||
logger.addContext('trNr', this.transactionInternNr)
|
||||
@ -96,11 +95,11 @@ export class HieroClient {
|
||||
.then(async (signedHieroTransaction) => {
|
||||
const sendResponse = await signedHieroTransaction.executeWithSigner(this.wallet)
|
||||
logger.info(
|
||||
`message sent to topic ${topicId}, transaction id: ${sendResponse.transactionId.toString()}`,
|
||||
`message sent to topic ${topicId}, transaction id: ${sendResponse.transactionId.toString()}, timeUsed: ${timeUsed.string()}`,
|
||||
)
|
||||
// TODO: fix issue in GradidoNode
|
||||
// hot fix, when gradido node is running some time, the hiero listener stop working, so we check if our new transaction is received
|
||||
// after 1 second, else restart GradidoNode
|
||||
// after 10 seconds, else restart GradidoNode
|
||||
setTimeout(async () => {
|
||||
const transaction = await GradidoNodeClient.getInstance().getTransaction({
|
||||
topic: topicId,
|
||||
@ -110,7 +109,7 @@ export class HieroClient {
|
||||
const process = GradidoNodeProcess.getInstance()
|
||||
const lastStarted = process.getLastStarted()
|
||||
if (lastStarted) {
|
||||
const serverRunTime = printTimeDuration(new Date().getTime() - lastStarted.getTime())
|
||||
const serverRunTime = printTimeDuration(durationInMinutesFromDates(lastStarted, new Date()))
|
||||
this.logger.error(`transaction not found, restart GradidoNode after ${serverRunTime}`)
|
||||
await GradidoNodeProcess.getInstance().restart()
|
||||
} else {
|
||||
@ -118,7 +117,7 @@ export class HieroClient {
|
||||
GradidoNodeProcess.getInstance().start()
|
||||
}
|
||||
}
|
||||
}, 1000)
|
||||
}, 10000)
|
||||
if (logger.isInfoEnabled()) {
|
||||
// only for logging
|
||||
sendResponse.getReceiptWithSigner(this.wallet).then((receipt) => {
|
||||
@ -127,9 +126,8 @@ export class HieroClient {
|
||||
// only for logging
|
||||
sendResponse.getRecordWithSigner(this.wallet).then((record) => {
|
||||
logger.info(`message sent, cost: ${record.transactionFee.toString()}`)
|
||||
const localEndTime = new Date()
|
||||
logger.info(
|
||||
`HieroClient.sendMessage used time (full process): ${localEndTime.getTime() - startTime.getTime()}ms`,
|
||||
`HieroClient.sendMessage used time (full process): ${timeUsed.string()}`,
|
||||
)
|
||||
})
|
||||
}
|
||||
@ -141,8 +139,7 @@ export class HieroClient {
|
||||
this.pendingPromises.splice(pendingPromiseIndex, 1)
|
||||
}),
|
||||
)
|
||||
const endTime = new Date()
|
||||
logger.info(`HieroClient.sendMessage used time: ${endTime.getTime() - startTime.getTime()}ms`)
|
||||
logger.debug(`create transactionId: ${hieroTransaction.transactionId?.toString()}, used time: ${timeUsed.string()}`)
|
||||
return hieroTransaction.transactionId
|
||||
}
|
||||
|
||||
|
||||
@ -16,6 +16,7 @@ export const GRADIDO_NODE_RUNTIME_PATH = path.join(
|
||||
)
|
||||
// if last start was less than this time, do not restart
|
||||
export const GRADIDO_NODE_MIN_RUNTIME_BEFORE_RESTART_MILLISECONDS = 1000 * 30
|
||||
export const GRADIDO_NODE_MIN_RUNTIME_BEFORE_EXIT_MILLISECONDS = 1000 * 2
|
||||
export const GRADIDO_NODE_KILL_TIMEOUT_MILLISECONDS = 10000
|
||||
// currently hard coded in gradido node, update in future
|
||||
export const GRADIDO_NODE_HOME_FOLDER_NAME = '.gradido'
|
||||
|
||||
@ -104,7 +104,7 @@ async function sendViaHiero(
|
||||
if (!transactionId) {
|
||||
throw new Error('missing transaction id from hiero')
|
||||
}
|
||||
logger.info('transmitted Gradido Transaction to Hiero', {
|
||||
logger.debug('give Gradido Transaction to Hiero Client', {
|
||||
transactionId: transactionId.toString(),
|
||||
})
|
||||
return v.parse(hieroTransactionIdStringSchema, transactionId.toString())
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import { promisify } from 'node:util'
|
||||
|
||||
/**
|
||||
* @param {number} time - in minutes
|
||||
*/
|
||||
@ -40,3 +42,5 @@ export const printTimeDuration = (duration: number): string => {
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
export const delay = promisify(setTimeout)
|
||||
Loading…
x
Reference in New Issue
Block a user