mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-18 02:21:13 +00:00
refactor(core): Move queueModeId as hostId to InstanceSettings (#11262)
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
import type { Redis as SingleNodeClient } from 'ioredis';
|
||||
import { mock } from 'jest-mock-extended';
|
||||
import type { InstanceSettings } from 'n8n-core';
|
||||
|
||||
import config from '@/config';
|
||||
import { generateNanoId } from '@/databases/utils/generators';
|
||||
import type { RedisClientService } from '@/services/redis-client.service';
|
||||
import { mockLogger } from '@test/mocking';
|
||||
|
||||
@@ -10,28 +10,26 @@ import { Publisher } from '../pubsub/publisher.service';
|
||||
import type { PubSub } from '../pubsub/pubsub.types';
|
||||
|
||||
describe('Publisher', () => {
|
||||
let queueModeId: string;
|
||||
|
||||
beforeEach(() => {
|
||||
config.set('executions.mode', 'queue');
|
||||
queueModeId = generateNanoId();
|
||||
config.set('redis.queueModeId', queueModeId);
|
||||
});
|
||||
|
||||
const client = mock<SingleNodeClient>();
|
||||
const logger = mockLogger();
|
||||
const hostId = 'main-bnxa1riryKUNHtln';
|
||||
const instanceSettings = mock<InstanceSettings>({ hostId });
|
||||
const redisClientService = mock<RedisClientService>({ createClient: () => client });
|
||||
|
||||
describe('constructor', () => {
|
||||
it('should init Redis client in scaling mode', () => {
|
||||
const publisher = new Publisher(logger, redisClientService);
|
||||
const publisher = new Publisher(logger, redisClientService, instanceSettings);
|
||||
|
||||
expect(publisher.getClient()).toEqual(client);
|
||||
});
|
||||
|
||||
it('should not init Redis client in regular mode', () => {
|
||||
config.set('executions.mode', 'regular');
|
||||
const publisher = new Publisher(logger, redisClientService);
|
||||
const publisher = new Publisher(logger, redisClientService, instanceSettings);
|
||||
|
||||
expect(publisher.getClient()).toBeUndefined();
|
||||
});
|
||||
@@ -39,7 +37,7 @@ describe('Publisher', () => {
|
||||
|
||||
describe('shutdown', () => {
|
||||
it('should disconnect Redis client', () => {
|
||||
const publisher = new Publisher(logger, redisClientService);
|
||||
const publisher = new Publisher(logger, redisClientService, instanceSettings);
|
||||
publisher.shutdown();
|
||||
expect(client.disconnect).toHaveBeenCalled();
|
||||
});
|
||||
@@ -47,21 +45,21 @@ describe('Publisher', () => {
|
||||
|
||||
describe('publishCommand', () => {
|
||||
it('should publish command into `n8n.commands` pubsub channel', async () => {
|
||||
const publisher = new Publisher(logger, redisClientService);
|
||||
const publisher = new Publisher(logger, redisClientService, instanceSettings);
|
||||
const msg = mock<PubSub.Command>({ command: 'reload-license' });
|
||||
|
||||
await publisher.publishCommand(msg);
|
||||
|
||||
expect(client.publish).toHaveBeenCalledWith(
|
||||
'n8n.commands',
|
||||
JSON.stringify({ ...msg, senderId: queueModeId, selfSend: false, debounce: true }),
|
||||
JSON.stringify({ ...msg, senderId: hostId, selfSend: false, debounce: true }),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('publishWorkerResponse', () => {
|
||||
it('should publish worker response into `n8n.worker-response` pubsub channel', async () => {
|
||||
const publisher = new Publisher(logger, redisClientService);
|
||||
const publisher = new Publisher(logger, redisClientService, instanceSettings);
|
||||
const msg = mock<PubSub.WorkerResponse>({
|
||||
response: 'response-to-get-worker-status',
|
||||
});
|
||||
|
||||
@@ -17,14 +17,14 @@ describe('Subscriber', () => {
|
||||
|
||||
describe('constructor', () => {
|
||||
it('should init Redis client in scaling mode', () => {
|
||||
const subscriber = new Subscriber(mock(), redisClientService, mock());
|
||||
const subscriber = new Subscriber(mock(), redisClientService, mock(), mock());
|
||||
|
||||
expect(subscriber.getClient()).toEqual(client);
|
||||
});
|
||||
|
||||
it('should not init Redis client in regular mode', () => {
|
||||
config.set('executions.mode', 'regular');
|
||||
const subscriber = new Subscriber(mock(), redisClientService, mock());
|
||||
const subscriber = new Subscriber(mock(), redisClientService, mock(), mock());
|
||||
|
||||
expect(subscriber.getClient()).toBeUndefined();
|
||||
});
|
||||
@@ -32,7 +32,7 @@ describe('Subscriber', () => {
|
||||
|
||||
describe('shutdown', () => {
|
||||
it('should disconnect Redis client', () => {
|
||||
const subscriber = new Subscriber(mock(), redisClientService, mock());
|
||||
const subscriber = new Subscriber(mock(), redisClientService, mock(), mock());
|
||||
subscriber.shutdown();
|
||||
expect(client.disconnect).toHaveBeenCalled();
|
||||
});
|
||||
@@ -40,7 +40,7 @@ describe('Subscriber', () => {
|
||||
|
||||
describe('subscribe', () => {
|
||||
it('should subscribe to pubsub channel', async () => {
|
||||
const subscriber = new Subscriber(mock(), redisClientService, mock());
|
||||
const subscriber = new Subscriber(mock(), redisClientService, mock(), mock());
|
||||
|
||||
await subscriber.subscribe('n8n.commands');
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { RunningJobSummary } from '@n8n/api-types';
|
||||
import { WorkflowExecute } from 'n8n-core';
|
||||
import { InstanceSettings, WorkflowExecute } from 'n8n-core';
|
||||
import { BINARY_ENCODING, ApplicationError, Workflow } from 'n8n-workflow';
|
||||
import type { ExecutionStatus, IExecuteResponsePromiseData, IRun } from 'n8n-workflow';
|
||||
import type PCancelable from 'p-cancelable';
|
||||
@@ -33,6 +33,7 @@ export class JobProcessor {
|
||||
private readonly executionRepository: ExecutionRepository,
|
||||
private readonly workflowRepository: WorkflowRepository,
|
||||
private readonly nodeTypes: NodeTypes,
|
||||
private readonly instanceSettings: InstanceSettings,
|
||||
) {
|
||||
this.logger = this.logger.withScope('scaling');
|
||||
}
|
||||
@@ -120,7 +121,7 @@ export class JobProcessor {
|
||||
kind: 'respond-to-webhook',
|
||||
executionId,
|
||||
response: this.encodeWebhookResponse(response),
|
||||
workerId: config.getEnv('redis.queueModeId'),
|
||||
workerId: this.instanceSettings.hostId,
|
||||
};
|
||||
|
||||
await job.progress(msg);
|
||||
@@ -173,7 +174,7 @@ export class JobProcessor {
|
||||
const msg: JobFinishedMessage = {
|
||||
kind: 'job-finished',
|
||||
executionId,
|
||||
workerId: config.getEnv('redis.queueModeId'),
|
||||
workerId: this.instanceSettings.hostId,
|
||||
};
|
||||
|
||||
await job.progress(msg);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { Redis as SingleNodeClient, Cluster as MultiNodeClient } from 'ioredis';
|
||||
import { InstanceSettings } from 'n8n-core';
|
||||
import { Service } from 'typedi';
|
||||
|
||||
import config from '@/config';
|
||||
@@ -20,6 +21,7 @@ export class Publisher {
|
||||
constructor(
|
||||
private readonly logger: Logger,
|
||||
private readonly redisClientService: RedisClientService,
|
||||
private readonly instanceSettings: InstanceSettings,
|
||||
) {
|
||||
// @TODO: Once this class is only ever initialized in scaling mode, throw in the next line instead.
|
||||
if (config.getEnv('executions.mode') !== 'queue') return;
|
||||
@@ -48,7 +50,7 @@ export class Publisher {
|
||||
'n8n.commands',
|
||||
JSON.stringify({
|
||||
...msg,
|
||||
senderId: config.getEnv('redis.queueModeId'),
|
||||
senderId: this.instanceSettings.hostId,
|
||||
selfSend: SELF_SEND_COMMANDS.has(msg.command),
|
||||
debounce: !IMMEDIATE_COMMANDS.has(msg.command),
|
||||
}),
|
||||
|
||||
@@ -3,7 +3,6 @@ import { ensureError } from 'n8n-workflow';
|
||||
import { Service } from 'typedi';
|
||||
|
||||
import { ActiveWorkflowManager } from '@/active-workflow-manager';
|
||||
import config from '@/config';
|
||||
import { WorkflowRepository } from '@/databases/repositories/workflow.repository';
|
||||
import { MessageEventBus } from '@/eventbus/message-event-bus/message-event-bus';
|
||||
import { EventService } from '@/events/event.service';
|
||||
@@ -49,7 +48,7 @@ export class PubSubHandler {
|
||||
...this.commonHandlers,
|
||||
'get-worker-status': async () =>
|
||||
await this.publisher.publishWorkerResponse({
|
||||
senderId: config.getEnv('redis.queueModeId'),
|
||||
senderId: this.instanceSettings.hostId,
|
||||
response: 'response-to-get-worker-status',
|
||||
payload: this.workerStatusService.generateStatus(),
|
||||
}),
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { Redis as SingleNodeClient, Cluster as MultiNodeClient } from 'ioredis';
|
||||
import debounce from 'lodash/debounce';
|
||||
import { InstanceSettings } from 'n8n-core';
|
||||
import { jsonParse } from 'n8n-workflow';
|
||||
import { Service } from 'typedi';
|
||||
|
||||
@@ -21,6 +22,7 @@ export class Subscriber {
|
||||
private readonly logger: Logger,
|
||||
private readonly redisClientService: RedisClientService,
|
||||
private readonly eventService: EventService,
|
||||
private readonly instanceSettings: InstanceSettings,
|
||||
) {
|
||||
// @TODO: Once this class is only ever initialized in scaling mode, throw in the next line instead.
|
||||
if (config.getEnv('executions.mode') !== 'queue') return;
|
||||
@@ -77,12 +79,12 @@ export class Subscriber {
|
||||
return null;
|
||||
}
|
||||
|
||||
const queueModeId = config.getEnv('redis.queueModeId');
|
||||
const { hostId } = this.instanceSettings;
|
||||
|
||||
if (
|
||||
'command' in msg &&
|
||||
!msg.selfSend &&
|
||||
(msg.senderId === queueModeId || (msg.targets && !msg.targets.includes(queueModeId)))
|
||||
(msg.senderId === hostId || (msg.targets && !msg.targets.includes(hostId)))
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@ export class ScalingService {
|
||||
const msg: JobFailedMessage = {
|
||||
kind: 'job-failed',
|
||||
executionId,
|
||||
workerId: config.getEnv('redis.queueModeId'),
|
||||
workerId: this.instanceSettings.hostId,
|
||||
errorMsg: error.message,
|
||||
};
|
||||
|
||||
|
||||
@@ -1,19 +1,22 @@
|
||||
import type { WorkerStatus } from '@n8n/api-types';
|
||||
import { InstanceSettings } from 'n8n-core';
|
||||
import os from 'node:os';
|
||||
import { Service } from 'typedi';
|
||||
|
||||
import config from '@/config';
|
||||
import { N8N_VERSION } from '@/constants';
|
||||
|
||||
import { JobProcessor } from './job-processor';
|
||||
|
||||
@Service()
|
||||
export class WorkerStatusService {
|
||||
constructor(private readonly jobProcessor: JobProcessor) {}
|
||||
constructor(
|
||||
private readonly jobProcessor: JobProcessor,
|
||||
private readonly instanceSettings: InstanceSettings,
|
||||
) {}
|
||||
|
||||
generateStatus(): WorkerStatus {
|
||||
return {
|
||||
senderId: config.getEnv('redis.queueModeId'),
|
||||
senderId: this.instanceSettings.hostId,
|
||||
runningJobsSummary: this.jobProcessor.getRunningJobsSummary(),
|
||||
freeMem: os.freemem(),
|
||||
totalMem: os.totalmem(),
|
||||
|
||||
Reference in New Issue
Block a user