diff --git a/components/client/typescript/src/index.ts b/components/client/typescript/src/index.ts index da193fc8..e6fc6730 100644 --- a/components/client/typescript/src/index.ts +++ b/components/client/typescript/src/index.ts @@ -6,6 +6,7 @@ import { Static, Type } from '@fastify/type-provider-typebox'; import { BitcoinIfThisOptionsSchema, BitcoinIfThisSchema } from './schemas/bitcoin/if_this'; import { StacksIfThisOptionsSchema, StacksIfThisSchema } from './schemas/stacks/if_this'; import { logger } from './util/logger'; +import { PredicateSchema } from './schemas/predicate'; const EventObserverOptionsSchema = Type.Object({ /** Event observer host name (usually '0.0.0.0') */ @@ -40,6 +41,9 @@ const EventObserverOptionsSchema = Type.Object({ * up to date. If they become obsolete, we will attempt to re-register them. */ predicate_health_check_interval_ms: Type.Optional(Type.Integer({ default: 5000 })), + predicate_re_register_callback: Type.Optional( + Type.Function([PredicateSchema], Type.Promise(PredicateSchema)) + ), }); /** Chainhook event observer configuration options */ export type EventObserverOptions = Static; @@ -126,14 +130,24 @@ export class ChainhookEventObserver { this.fastify = await buildServer(this.observer, this.chainhook, predicates, callback); await this.fastify.listen({ host: this.observer.hostname, port: this.observer.port }); if (this.observer.predicate_health_check_interval_ms && this.healthCheckTimer === undefined) { - this.healthCheckTimer = setInterval(() => { - predicateHealthCheck(this.observer, this.chainhook).catch(err => - logger.error(err, `ChainhookEventObserver predicate health check error`) - ); - }, this.observer.predicate_health_check_interval_ms); + this.scheduleHealthCheck(); } } + private scheduleHealthCheck() { + this.healthCheckTimer = setTimeout(() => { + void predicateHealthCheck(this.observer, this.chainhook) + .catch(err => { + logger.error(err, `ChainhookEventObserver predicate health check error`); + }) + .finally(() => { + if (this.healthCheckTimer) { + this.scheduleHealthCheck(); + } + }); + }, this.observer.predicate_health_check_interval_ms); + } + /** * Stop the Chainhook event server gracefully. */ diff --git a/components/client/typescript/src/predicates.ts b/components/client/typescript/src/predicates.ts index 93d08ed4..b56cc3c6 100644 --- a/components/client/typescript/src/predicates.ts +++ b/components/client/typescript/src/predicates.ts @@ -146,11 +146,15 @@ async function registerPredicate( authorization_header: `Bearer ${observer.auth_token}`, }, }; - const newPredicate = pendingPredicate as Predicate; + let newPredicate = pendingPredicate as Predicate; newPredicate.uuid = randomUUID(); if (newPredicate.networks.mainnet) newPredicate.networks.mainnet.then_that = thenThat; if (newPredicate.networks.testnet) newPredicate.networks.testnet.then_that = thenThat; + if (observer.predicate_re_register_callback) { + newPredicate = await observer.predicate_re_register_callback(newPredicate); + } + const path = observer.node_type === 'chainhook' ? `/v1/chainhooks` : `/v1/observers`; await request(`${chainhook.base_url}${path}`, { method: 'POST',