UNPKG

status-sharding

Version:

Welcome to Status Sharding! This package is designed to provide an efficient and flexible solution for sharding Discord bots, allowing you to scale your bot across multiple processes or workers.

85 lines 4.71 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.HeartbeatManager = void 0; const shardingUtils_1 = require("../other/shardingUtils"); const types_1 = require("../types"); /** Handles heartbeats for the cluster manager. */ class HeartbeatManager { manager; /** The interval of the heartbeat. */ interval; /** The list of heartbeat data per cluster. */ beats; /** Creates an instance of HeartbeatManager. */ constructor(manager) { this.manager = manager; if (this.manager.options.heartbeat.interval <= 0) throw new Error('The heartbeat interval must be greater than 0.'); else if (this.manager.options.heartbeat.timeout <= 0) throw new Error('The heartbeat timeout must be greater than 0.'); else if (this.manager.options.heartbeat.interval >= this.manager.options.heartbeat.timeout) throw new Error('The heartbeat timeout must be greater than the heartbeat interval.'); this.beats = new Map(); this.interval = setInterval(() => { for (const cluster of this.manager.clusters.values()) { const shouldSend = cluster.ready ? true : cluster.exited; this.manager._debug(`Cluster ${cluster.id} heartbeat check (${shardingUtils_1.ShardingUtils.boolProp(cluster.ready, 'ready')}, ${shardingUtils_1.ShardingUtils.boolProp(cluster.exited, 'exited')}, ${shardingUtils_1.ShardingUtils.boolProp(this.beats.get(cluster.id)?.killing, 'killing')}, ${shardingUtils_1.ShardingUtils.relativeTime(cluster.lastHeartbeatReceived)})`); if ((!shouldSend && !this.beats.get(cluster.id)?.killing) || !cluster.lastHeartbeatReceived) continue; cluster._sendInstance({ _type: types_1.MessageTypes.Heartbeat })?.catch(() => null); if (Date.now() - cluster.lastHeartbeatReceived > this.manager.options.heartbeat.timeout) { this.manager._debug(`Cluster ${cluster.id} has missed a heartbeat. (${this.getClusterStats(cluster.id).missedBeats} missed)`); this.addMissedBeat(cluster.id); } else { const clusterData = this.getClusterStats(cluster.id); if (clusterData.missedBeats > 0) { clusterData.missedBeats = 0; this.beats.set(cluster.id, clusterData); } this.manager._debug(`Cluster ${cluster.id} has received a heartbeat.`); } } }, this.manager.options.heartbeat.interval); } /** Stops the heartbeat. */ stop() { clearInterval(this.interval); } /** Gets the heartbeat data for a cluster. */ getClusterStats(id) { return this.beats.get(id) || this.beats.set(id, { missedBeats: 0, restarts: 0, killing: false }).get(id); } /** Removes a cluster from the heartbeat. */ removeCluster(id) { this.beats.delete(id); } /** Adds a missed beat to a cluster. */ async addMissedBeat(id) { const cluster = this.getClusterStats(id); cluster.missedBeats++; if (cluster.missedBeats >= this.manager.options.heartbeat.maxMissedHeartbeats) { const targetCluster = this.manager.clusters.get(id); if (!targetCluster) throw new Error(`Cluster ${id} not found for heartbeat.`); this.beats.set(id, { ...cluster, killing: true }); this.manager._debug(`Cluster ${id} has missed too many heartbeats. (${cluster.missedBeats})`); if (targetCluster.thread) await targetCluster?.kill({ reason: 'Missed too many heartbeats.' }); this.beats.set(id, { ...cluster, killing: false }); if (cluster.restarts < this.manager.options.heartbeat.maxRestarts || this.manager.options.heartbeat.maxRestarts !== -1) { this.manager._debug(`Cluster ${id} is restarting.. (${this.manager.options.heartbeat.maxRestarts !== -1 ? this.manager.options.heartbeat.maxRestarts - cluster.restarts : 'unlimited'} left)`); if (!targetCluster.thread) await targetCluster?.spawn(); cluster.missedBeats = 0; cluster.restarts++; } else this.manager._debug(`Cluster ${id} reached the maximum amount of restarts (${cluster.restarts}).`); } this.manager._debug(`Cluster ${id} has missed a heartbeat. (${cluster.missedBeats} missed)`); this.beats.set(id, cluster); } } exports.HeartbeatManager = HeartbeatManager; //# sourceMappingURL=heartbeat.js.map