diff --git a/ci/config.json.ci b/ci/config.json.ci index 8f072010e..5a6fe26d0 100644 --- a/ci/config.json.ci +++ b/ci/config.json.ci @@ -184,6 +184,9 @@ "millisecondRepeatJob": 2000, "blocksPerCall": 100 }, + "servicesManager": { + "healthCheckLimit": 100 + }, "crawlIbcApp": { "key": "crawlIbcApp", "millisecondRepeatJob": 2000, diff --git a/config.json b/config.json index 3854081fc..fdda14af6 100644 --- a/config.json +++ b/config.json @@ -184,6 +184,9 @@ "millisecondRepeatJob": 2000, "blocksPerCall": 100 }, + "servicesManager": { + "healthCheckLimit": 100 + }, "crawlIbcApp": { "key": "crawlIbcApp", "millisecondRepeatJob": 2000, diff --git a/src/common/constant.ts b/src/common/constant.ts index 7980dddc5..e6334dee8 100644 --- a/src/common/constant.ts +++ b/src/common/constant.ts @@ -274,6 +274,14 @@ export const SERVICE = { path: 'v1.Cw20ReindexingService.reindexing', }, }, + ServicesManager: { + key: 'ServicesManager', + name: 'v1.ServicesManager', + HealthCheck: { + key: 'HealthCheck', + path: 'v1.ServicesManager.HealthCheck', + }, + }, }, }; diff --git a/src/services/api-gateways/api_gateway.service.ts b/src/services/api-gateways/api_gateway.service.ts index 5021b71ab..23d46a48d 100644 --- a/src/services/api-gateways/api_gateway.service.ts +++ b/src/services/api-gateways/api_gateway.service.ts @@ -25,6 +25,7 @@ import { bullBoardMixin } from '../../mixins/bullBoard/bullBoard.mixin'; 'v2.graphql.*', 'v2.statistics.getDashboardStatisticsByChainId', 'v2.statistics.getTopAccountsByChainId', + 'v1.services-manager.*', ], }, { diff --git a/src/services/api-gateways/services-manager.service.ts b/src/services/api-gateways/services-manager.service.ts new file mode 100644 index 000000000..cd1885216 --- /dev/null +++ b/src/services/api-gateways/services-manager.service.ts @@ -0,0 +1,51 @@ +import { Get, Service } from '@ourparentcenter/moleculer-decorators-extended'; +import { Context, ServiceBroker } from 'moleculer'; +import networks from '../../../network.json' assert { type: 'json' }; +import BaseService from '../../base/base.service'; +import { BULL_JOB_NAME } from '../../common'; + +@Service({ + name: 'services-manager', + version: 1, +}) +export default class ServicesManagerService extends BaseService { + public constructor(public broker: ServiceBroker) { + super(broker); + } + + @Get('/health-check', { + name: 'healthCheck', + params: { + chainid: { + type: 'string', + optional: false, + enum: networks.map((network) => network.chainId), + }, + jobNames: { + type: 'array', + optional: false, + items: 'string', + enum: Object.values(BULL_JOB_NAME), + }, + }, + }) + async healthCheck( + ctx: Context< + { + chainid: string; + jobNames: string[]; + }, + Record + > + ) { + const selectedChain = networks.find( + (network) => network.chainId === ctx.params.chainid + ); + return this.broker.call( + `v1.ServicesManager.HealthCheck@${selectedChain?.moleculerNamespace}`, + { + jobNames: ctx.params.jobNames, + } + ); + } +} diff --git a/src/services/manager/services-manager.service.ts b/src/services/manager/services-manager.service.ts new file mode 100644 index 000000000..8d3a2ab4d --- /dev/null +++ b/src/services/manager/services-manager.service.ts @@ -0,0 +1,50 @@ +import { + Action, + Service, +} from '@ourparentcenter/moleculer-decorators-extended'; +import { Context, ServiceBroker } from 'moleculer'; +import config from '../../../config.json' assert { type: 'json' }; +import BullableService from '../../base/bullable.service'; +import { BULL_JOB_NAME, SERVICE } from '../../common'; +import { BlockCheckpoint } from '../../models'; + +@Service({ + name: SERVICE.V1.ServicesManager.key, + version: 1, +}) +export default class ServicesManagerService extends BullableService { + public constructor(public broker: ServiceBroker) { + super(broker); + } + + @Action({ + name: SERVICE.V1.ServicesManager.HealthCheck.key, + params: { + jobNames: { + type: 'array', + optional: false, + items: 'string', + }, + }, + }) + public async actionHealthCheck(ctx: Context<{ jobNames: string[] }>) { + const { jobNames } = ctx.params; + const result: Record = {}; + const jobBlock = await BlockCheckpoint.query() + .where('job_name', BULL_JOB_NAME.CRAWL_BLOCK) + .first() + .throwIfNotFound(); + const jobsHeight = await BlockCheckpoint.query().whereIn( + 'job_name', + jobNames + ); + jobsHeight.forEach((job) => { + Object.assign(result, { + [job.job_name]: + jobBlock.height - job.height < + config.servicesManager.healthCheckLimit, + }); + }); + return result; + } +}