mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-16 17:46:45 +00:00
Story: https://linear.app/n8n/issue/PAY-926 This PR coordinates workflow activation on instance startup and on leadership change in multiple main scenario in the internal API. Part 3 on manual workflow activation and deactivation will be a separate PR. ### Part 1: Instance startup In multi-main scenario, on starting an instance... - [x] If the instance is the leader, it should add webhooks, triggers and pollers. - [x] If the instance is the follower, it should not add webhooks, triggers or pollers. - [x] Unit tests. ### Part 2: Leadership change In multi-main scenario, if the main instance leader dies… - [x] The new main instance leader must activate all trigger- and poller-based workflows, excluding webhook-based workflows. - [x] The old main instance leader must deactivate all trigger- and poller-based workflows, excluding webhook-based workflows. - [x] Unit tests. To test, start two instances and check behavior on startup and leadership change: ``` EXECUTIONS_MODE=queue N8N_LEADER_SELECTION_ENABLED=true N8N_LICENSE_TENANT_ID=... N8N_LICENSE_ACTIVATION_KEY=... N8N_LOG_LEVEL=debug npm run start EXECUTIONS_MODE=queue N8N_LEADER_SELECTION_ENABLED=true N8N_LICENSE_TENANT_ID=... N8N_LICENSE_ACTIVATION_KEY=... N8N_LOG_LEVEL=debug N8N_PORT=5679 npm run start ```
56 lines
1.3 KiB
TypeScript
56 lines
1.3 KiB
TypeScript
import Container from 'typedi';
|
|
import { RedisService } from './redis.service';
|
|
import type { RedisServicePubSubPublisher } from './redis/RedisServicePubSubPublisher';
|
|
import config from '@/config';
|
|
import { EventEmitter } from 'node:events';
|
|
|
|
export abstract class OrchestrationService extends EventEmitter {
|
|
protected initialized = false;
|
|
|
|
protected queueModeId: string;
|
|
|
|
redisPublisher: RedisServicePubSubPublisher;
|
|
|
|
readonly redisService: RedisService;
|
|
|
|
get isQueueMode(): boolean {
|
|
return config.get('executions.mode') === 'queue';
|
|
}
|
|
|
|
get isMainInstance(): boolean {
|
|
return config.get('generic.instanceType') === 'main';
|
|
}
|
|
|
|
get isWebhookInstance(): boolean {
|
|
return config.get('generic.instanceType') === 'webhook';
|
|
}
|
|
|
|
get isWorkerInstance(): boolean {
|
|
return config.get('generic.instanceType') === 'worker';
|
|
}
|
|
|
|
constructor() {
|
|
super();
|
|
this.redisService = Container.get(RedisService);
|
|
this.queueModeId = config.getEnv('redis.queueModeId');
|
|
}
|
|
|
|
sanityCheck(): boolean {
|
|
return this.initialized && this.isQueueMode;
|
|
}
|
|
|
|
async init() {
|
|
await this.initPublisher();
|
|
this.initialized = true;
|
|
}
|
|
|
|
async shutdown() {
|
|
await this.redisPublisher?.destroy();
|
|
this.initialized = false;
|
|
}
|
|
|
|
protected async initPublisher() {
|
|
this.redisPublisher = await this.redisService.getPubSubPublisher();
|
|
}
|
|
}
|