1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-02-09 00:18:00 +01:00

feat: scheduler init jitter (#6071)

This commit is contained in:
Mateusz Kwasniewski 2024-01-30 15:49:35 +01:00 committed by GitHub
parent 55b2bb4813
commit ccc41dca4e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 50 additions and 3 deletions

View File

@ -72,7 +72,7 @@ test('Schedules job immediately', async () => {
const job = jest.fn(); const job = jest.fn();
await schedulerService.schedule(job, 10, 'test-id'); await schedulerService.schedule(job, 10, 'test-id', 0);
expect(job).toBeCalledTimes(1); expect(job).toBeCalledTimes(1);
schedulerService.stop(); schedulerService.stop();
@ -172,7 +172,7 @@ test('Can handle crash of a async job', async () => {
await Promise.reject('async reason'); await Promise.reject('async reason');
}; };
await schedulerService.schedule(job, 50, 'test-id-10'); await schedulerService.schedule(job, 50, 'test-id-10', 0);
await ms(75); await ms(75);
schedulerService.stop(); schedulerService.stop();
@ -236,3 +236,29 @@ it('should emit scheduler job time event when scheduled function is run', async
await schedulerService.schedule(mockJob, 50, 'testJobId'); await schedulerService.schedule(mockJob, 50, 'testJobId');
await eventPromise; await eventPromise;
}); });
test('Delays initial job execution by jitter duration', async () => {
const { schedulerService } = createSchedulerTestService();
const job = jest.fn();
const jitterMs = 10;
await schedulerService.schedule(job, 10000, 'test-id', jitterMs);
expect(job).toBeCalledTimes(0);
await ms(50);
expect(job).toBeCalledTimes(1);
schedulerService.stop();
});
test('Does not apply jitter if schedule interval is smaller than max jitter', async () => {
const { schedulerService } = createSchedulerTestService();
const job = jest.fn();
// default jitter 2s-30s
await schedulerService.schedule(job, 1000, 'test-id');
expect(job).toBeCalledTimes(1);
schedulerService.stop();
});

View File

@ -3,6 +3,19 @@ import { Logger, LogProvider } from '../../logger';
import { IMaintenanceStatus } from '../maintenance/maintenance-service'; import { IMaintenanceStatus } from '../maintenance/maintenance-service';
import { SCHEDULER_JOB_TIME } from '../../metric-events'; import { SCHEDULER_JOB_TIME } from '../../metric-events';
// returns between min and max seconds in ms
// when schedule interval is smaller than max jitter then no jitter
function randomJitter(
minMs: number,
maxMs: number,
scheduleIntervalMs: number,
): number {
if (scheduleIntervalMs < maxMs) {
return 0;
}
return Math.random() * (maxMs - minMs) + minMs;
}
export class SchedulerService { export class SchedulerService {
private intervalIds: NodeJS.Timeout[] = []; private intervalIds: NodeJS.Timeout[] = [];
@ -26,6 +39,7 @@ export class SchedulerService {
scheduledFunction: () => void, scheduledFunction: () => void,
timeMs: number, timeMs: number,
id: string, id: string,
jitter = randomJitter(2 * 1000, 30 * 1000, timeMs),
): Promise<void> { ): Promise<void> {
const runScheduledFunctionWithEvent = async () => { const runScheduledFunctionWithEvent = async () => {
const startTime = process.hrtime(); const startTime = process.hrtime();
@ -61,8 +75,15 @@ export class SchedulerService {
try { try {
const maintenanceMode = const maintenanceMode =
await this.maintenanceStatus.isMaintenanceMode(); await this.maintenanceStatus.isMaintenanceMode();
if (!maintenanceMode) { if (!maintenanceMode) {
await runScheduledFunctionWithEvent(); if (jitter) {
setTimeout(() => {
runScheduledFunctionWithEvent();
}, jitter);
} else {
await runScheduledFunctionWithEvent();
}
} }
} catch (e) { } catch (e) {
this.logger.error(`initial scheduled job failed | id: ${id}`, e); this.logger.error(`initial scheduled job failed | id: ${id}`, e);