diff --git a/packages/beacon-node/src/monitoring/service.ts b/packages/beacon-node/src/monitoring/service.ts index 4a2a155b681b..75f5e28c1b66 100644 --- a/packages/beacon-node/src/monitoring/service.ts +++ b/packages/beacon-node/src/monitoring/service.ts @@ -89,9 +89,9 @@ export class MonitoringService { } /** - * Stop sending client stats + * Stop sending client stats and wait for any pending request to complete */ - close(): void { + async close(): Promise { if (this.status === Status.Closed) return; this.status = Status.Closed; @@ -103,6 +103,7 @@ export class MonitoringService { } if (this.pendingRequest) { this.fetchAbortController?.abort(FetchAbortReason.Close); + await this.pendingRequest; } } diff --git a/packages/beacon-node/src/node/nodejs.ts b/packages/beacon-node/src/node/nodejs.ts index 0a3c321d16c7..56e33c3179de 100644 --- a/packages/beacon-node/src/node/nodejs.ts +++ b/packages/beacon-node/src/node/nodejs.ts @@ -360,9 +360,12 @@ export class BeaconNode { if (this.restApi) await this.restApi.close(); await this.network.close(); if (this.metricsServer) await this.metricsServer.close(); - if (this.monitoring) this.monitoring.close(); + if (this.monitoring) await this.monitoring.close(); await this.chain.persistToDisk(); await this.chain.close(); + // Abort signal last: close() calls above clear intervals/timeouts so no new + // operations get scheduled. If we aborted first, a still-pending interval could + // fire and schedule a new operation after abort, leaving it stuck and delaying shutdown. if (this.controller) this.controller.abort(); await sleep(DELAY_BEFORE_CLOSING_DB_MS); await this.db.close();