mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-18 18:41:14 +00:00
refactor(core): Move queue recovery to scaling service (no-changelog) (#10368)
This commit is contained in:
@@ -7,6 +7,9 @@ import type { Job, JobData, JobOptions, JobQueue } from '../types';
|
||||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { mockInstance } from '@test/mocking';
|
||||
import { GlobalConfig } from '@n8n/config';
|
||||
import { InstanceSettings } from 'n8n-core';
|
||||
import type { OrchestrationService } from '@/services/orchestration.service';
|
||||
import Container from 'typedi';
|
||||
import type { JobProcessor } from '../job-processor';
|
||||
|
||||
const queue = mock<JobQueue>({
|
||||
@@ -34,9 +37,27 @@ describe('ScalingService', () => {
|
||||
},
|
||||
});
|
||||
|
||||
const instanceSettings = Container.get(InstanceSettings);
|
||||
const orchestrationService = mock<OrchestrationService>({ isMultiMainSetupEnabled: false });
|
||||
const jobProcessor = mock<JobProcessor>();
|
||||
let scalingService: ScalingService;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
config.set('generic.instanceType', 'main');
|
||||
scalingService = new ScalingService(
|
||||
mock(),
|
||||
mock(),
|
||||
jobProcessor,
|
||||
globalConfig,
|
||||
mock(),
|
||||
instanceSettings,
|
||||
orchestrationService,
|
||||
);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
scalingService.stopQueueRecovery();
|
||||
});
|
||||
|
||||
describe('setupQueue', () => {
|
||||
@@ -44,7 +65,6 @@ describe('ScalingService', () => {
|
||||
/**
|
||||
* Arrange
|
||||
*/
|
||||
const scalingService = new ScalingService(mock(), mock(), mock(), globalConfig);
|
||||
const { prefix, settings } = globalConfig.queue.bull;
|
||||
const Bull = jest.mocked(BullModule.default);
|
||||
|
||||
@@ -72,7 +92,15 @@ describe('ScalingService', () => {
|
||||
* Arrange
|
||||
*/
|
||||
config.set('generic.instanceType', 'worker');
|
||||
const scalingService = new ScalingService(mock(), mock(), mock(), globalConfig);
|
||||
const scalingService = new ScalingService(
|
||||
mock(),
|
||||
mock(),
|
||||
mock(),
|
||||
globalConfig,
|
||||
mock(),
|
||||
instanceSettings,
|
||||
orchestrationService,
|
||||
);
|
||||
await scalingService.setupQueue();
|
||||
const concurrency = 5;
|
||||
|
||||
@@ -91,7 +119,6 @@ describe('ScalingService', () => {
|
||||
/**
|
||||
* Arrange
|
||||
*/
|
||||
const scalingService = new ScalingService(mock(), mock(), mock(), globalConfig);
|
||||
await scalingService.setupQueue();
|
||||
|
||||
/**
|
||||
@@ -102,14 +129,13 @@ describe('ScalingService', () => {
|
||||
});
|
||||
|
||||
describe('stop', () => {
|
||||
it('should pause the queue and check for running jobs', async () => {
|
||||
it('should pause the queue, check for running jobs, and stop queue recovery', async () => {
|
||||
/**
|
||||
* Arrange
|
||||
*/
|
||||
const jobProcessor = mock<JobProcessor>();
|
||||
const scalingService = new ScalingService(mock(), mock(), jobProcessor, globalConfig);
|
||||
await scalingService.setupQueue();
|
||||
jobProcessor.getRunningJobIds.mockReturnValue([]);
|
||||
const stopQueueRecoverySpy = jest.spyOn(scalingService, 'stopQueueRecovery');
|
||||
const getRunningJobsCountSpy = jest.spyOn(scalingService, 'getRunningJobsCount');
|
||||
|
||||
/**
|
||||
@@ -121,6 +147,7 @@ describe('ScalingService', () => {
|
||||
* Assert
|
||||
*/
|
||||
expect(queue.pause).toHaveBeenCalledWith(true, true);
|
||||
expect(stopQueueRecoverySpy).toHaveBeenCalled();
|
||||
expect(getRunningJobsCountSpy).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -130,7 +157,6 @@ describe('ScalingService', () => {
|
||||
/**
|
||||
* Arrange
|
||||
*/
|
||||
const scalingService = new ScalingService(mock(), mock(), mock(), globalConfig);
|
||||
await scalingService.setupQueue();
|
||||
|
||||
/**
|
||||
@@ -150,7 +176,6 @@ describe('ScalingService', () => {
|
||||
/**
|
||||
* Arrange
|
||||
*/
|
||||
const scalingService = new ScalingService(mock(), mock(), mock(), globalConfig);
|
||||
await scalingService.setupQueue();
|
||||
queue.add.mockResolvedValue(mock<Job>({ id: '456' }));
|
||||
|
||||
@@ -173,7 +198,6 @@ describe('ScalingService', () => {
|
||||
/**
|
||||
* Arrange
|
||||
*/
|
||||
const scalingService = new ScalingService(mock(), mock(), mock(), globalConfig);
|
||||
await scalingService.setupQueue();
|
||||
const jobId = '123';
|
||||
queue.getJob.mockResolvedValue(mock<Job>({ id: jobId }));
|
||||
@@ -196,7 +220,6 @@ describe('ScalingService', () => {
|
||||
/**
|
||||
* Arrange
|
||||
*/
|
||||
const scalingService = new ScalingService(mock(), mock(), mock(), globalConfig);
|
||||
await scalingService.setupQueue();
|
||||
queue.getJobs.mockResolvedValue([mock<Job>({ id: '123' })]);
|
||||
|
||||
@@ -217,7 +240,6 @@ describe('ScalingService', () => {
|
||||
/**
|
||||
* Arrange
|
||||
*/
|
||||
const scalingService = new ScalingService(mock(), mock(), mock(), globalConfig);
|
||||
await scalingService.setupQueue();
|
||||
// @ts-expect-error - Untyped but possible Redis response
|
||||
queue.getJobs.mockResolvedValue([mock<Job>(), null]);
|
||||
@@ -239,7 +261,6 @@ describe('ScalingService', () => {
|
||||
/**
|
||||
* Arrange
|
||||
*/
|
||||
const scalingService = new ScalingService(mock(), mock(), mock(), globalConfig);
|
||||
await scalingService.setupQueue();
|
||||
const job = mock<Job>({ isActive: jest.fn().mockResolvedValue(true) });
|
||||
|
||||
@@ -259,7 +280,6 @@ describe('ScalingService', () => {
|
||||
/**
|
||||
* Arrange
|
||||
*/
|
||||
const scalingService = new ScalingService(mock(), mock(), mock(), globalConfig);
|
||||
await scalingService.setupQueue();
|
||||
const job = mock<Job>({ isActive: jest.fn().mockResolvedValue(false) });
|
||||
|
||||
@@ -279,7 +299,6 @@ describe('ScalingService', () => {
|
||||
/**
|
||||
* Arrange
|
||||
*/
|
||||
const scalingService = new ScalingService(mock(), mock(), mock(), globalConfig);
|
||||
await scalingService.setupQueue();
|
||||
const job = mock<Job>({
|
||||
isActive: jest.fn().mockImplementation(() => {
|
||||
@@ -298,4 +317,42 @@ describe('ScalingService', () => {
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('scheduleQueueRecovery', () => {
|
||||
it('if leader, should schedule queue recovery', async () => {
|
||||
/**
|
||||
* Arrange
|
||||
*/
|
||||
const scheduleSpy = jest.spyOn(scalingService, 'scheduleQueueRecovery');
|
||||
instanceSettings.markAsLeader();
|
||||
|
||||
/**
|
||||
* Act
|
||||
*/
|
||||
await scalingService.setupQueue();
|
||||
|
||||
/**
|
||||
* Assert
|
||||
*/
|
||||
expect(scheduleSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('if follower, should not schedule queue recovery', async () => {
|
||||
/**
|
||||
* Arrange
|
||||
*/
|
||||
const scheduleSpy = jest.spyOn(scalingService, 'scheduleQueueRecovery');
|
||||
instanceSettings.markAsFollower();
|
||||
|
||||
/**
|
||||
* Act
|
||||
*/
|
||||
await scalingService.setupQueue();
|
||||
|
||||
/**
|
||||
* Assert
|
||||
*/
|
||||
expect(scheduleSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user