n8n
Version:
n8n Workflow Automation Tool
143 lines • 5.56 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.MultiMainSetupV2 = void 0;
const node_assert_1 = __importDefault(require("node:assert"));
class MultiMainSetupV2 {
get hostId() {
return this.instanceSettings.hostId;
}
constructor(logger, instanceSettings, errorReporter, client, emit) {
this.logger = logger;
this.instanceSettings = instanceSettings;
this.errorReporter = errorReporter;
this.client = client;
this.emit = emit;
this.leaderCheckInProgress = false;
}
async init() {
const result = await this.client.setLeaderIfNotExists();
if (!result.ok) {
this.logRedisCommandFailure('Failed to set leader key in Redis during init', result.error);
this.instanceSettings.markAsFollower();
}
else if (result.result) {
this.takeOverAsLeader();
}
else {
this.instanceSettings.markAsFollower();
}
}
async shutdown() {
const { isLeader } = this.instanceSettings;
if (isLeader) {
const result = await this.client.clearLeader();
if (!result.ok) {
this.logger.warn('Failed to clear leader key from Redis', { error: result.error });
}
}
this.client.destroy();
}
async checkLeader() {
if (this.leaderCheckInProgress) {
this.logger.warn('Previous leader check is still in progress, skipping this check');
return;
}
this.leaderCheckInProgress = true;
try {
if (this.instanceSettings.isLeader) {
await this.checkAreWeStillLeader();
}
else {
await this.checkCanBecomeLeader();
}
}
finally {
this.leaderCheckInProgress = false;
}
}
async checkAreWeStillLeader() {
(0, node_assert_1.default)(this.instanceSettings.isLeader);
const renewTtlResult = await this.client.tryRenewLeaderTtl();
if (!renewTtlResult.ok) {
this.logRedisCommandFailure('Failed to renew leader TTL', renewTtlResult.error);
return;
}
const renewalResult = renewTtlResult.result;
if (renewalResult.id === 'success') {
this.logger.debug(`[Instance ID ${this.hostId}] Leader is this instance`);
return;
}
this.logger.warn('[Multi-main setup] Leader failed to renew leader key');
if (renewalResult.id === 'other-host-is-leader') {
this.logger.debug(`[Instance ID ${this.hostId}] Leader is other instance "${renewalResult.currentLeaderId}"`);
this.stepDownToFollower();
return;
}
(0, node_assert_1.default)(renewalResult.id === 'key-missing');
const result = await this.client.setLeaderIfNotExists();
if (!result.ok) {
this.logRedisCommandFailure('Failed to set leader key in Redis', result.error);
this.stepDownToFollower();
return;
}
const wasSet = result.result;
if (!wasSet) {
this.stepDownToFollower();
}
}
async checkCanBecomeLeader() {
(0, node_assert_1.default)(!this.instanceSettings.isLeader);
const getResult = await this.client.getLeader();
if (!getResult.ok) {
this.logRedisCommandFailure('Failed to get leader key from Redis', getResult.error);
return;
}
const leaderId = getResult.result;
if (leaderId && leaderId === this.hostId) {
this.errorReporter.info(`[Instance ID ${this.hostId}] Remote/Local leadership mismatch, marking self as leader`, {
shouldBeLogged: true,
shouldReport: true,
});
this.takeOverAsLeader();
return;
}
if (leaderId) {
this.logger.debug(`[Instance ID ${this.hostId}] Leader is other instance "${leaderId}"`);
return;
}
this.logger.debug(`[Instance ID ${this.hostId}] Leadership vacant, attempting to become leader...`);
const result = await this.client.setLeaderIfNotExists();
if (!result.ok) {
this.logger.warn('Failed to try leader key set in Redis', { error: result.error });
return;
}
const wasSet = result.result;
if (wasSet) {
this.takeOverAsLeader();
}
}
takeOverAsLeader() {
(0, node_assert_1.default)(!this.instanceSettings.isLeader);
this.logger.info(`[Instance ID ${this.hostId}] Leader is now this instance`);
this.instanceSettings.markAsLeader();
this.emit('leader-takeover');
}
stepDownToFollower() {
(0, node_assert_1.default)(this.instanceSettings.isLeader);
this.logger.info(`[Instance ID ${this.hostId}] This is now a follower instance`);
this.instanceSettings.markAsFollower();
this.emit('leader-stepdown');
}
async fetchLeaderKey() {
const result = await this.client.getLeader();
return result.ok ? result.result : null;
}
logRedisCommandFailure(message, error) {
this.logger.warn(`${message}: ${error.message}`, { error });
}
}
exports.MultiMainSetupV2 = MultiMainSetupV2;
//# sourceMappingURL=multi-main-setup-v2.js.map