Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

build(schedule): replace dependency cron with croner #1165

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 34 additions & 3 deletions lib/decorators/cron.decorator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,18 @@ export interface CronOptions {
name?: string;

/**
* Specify the timezone for the execution. This will modify the actual time relative to your timezone. If the timezone is invalid, an error is thrown. You can check all timezones available at [Moment Timezone Website](http://momentjs.com/timezone/). Probably don't use both ```timeZone``` and ```utcOffset``` together or weird things may happen.
* Specify the timezone for the execution. This will modify the actual time relative to your timezone. If the timezone is invalid, an error is thrown. You can check all timezones available at [Moment Timezone Website](http://momentjs.com/timezone/). Code will throw if trying to use both ```timeZone``` and ```utcOffset``` together.
*/
timeZone?: string;

/**
* This allows you to specify the offset of your timezone rather than using the ```timeZone``` param. Probably don't use both ```timeZone``` and ```utcOffset``` together or weird things may happen.
* This allows you to specify the offset of your timezone rather than using the ```timeZone``` param. Code will throw if trying to use both ```timeZone``` and ```utcOffset``` together.
*/
utcOffset?: string | number;
utcOffset?: number;

/**
* If you have code that keeps the event loop running and want to stop the node process when that finishes regardless of the state of your cronjob, you can do so making use of this parameter. This is off by default and cron will run as if it needs to control the event loop. For more information take a look at [timers#timers_timeout_unref](https://nodejs.org/api/timers.html#timers_timeout_unref) from the NodeJS docs.
* @default false
*/
unrefTimeout?: boolean;

Expand All @@ -35,6 +36,36 @@ export interface CronOptions {
* @default false
*/
disabled?: boolean;

/**
* Will skip executions until the previous execution is finished, in case of long running jobs.
* @default false
*/
preventOverrun?: boolean;

/**
* Specify a minimum interval between executions, in addition to your pattern. Specified in milliseconds.
* @default 0
*/
interval?: number;

/**
* Allows passing an arbitrary object to the triggered function, will be passed as the second argument.
* @default undefined
*/
context?: unknown;

/**
* Set maximum number of executions before the job is canceled.
* @default undefined
*/
maxRuns?: number;

/**
* Change how day-of-month and day-of-week are combined. Legacy Mode (default, true) = OR. Alternative mode (false) = AND
* @default true
*/
legacyMode?: boolean;
}

/**
Expand Down
36 changes: 20 additions & 16 deletions lib/scheduler.orchestrator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ import {
Injectable,
OnApplicationBootstrap,
OnApplicationShutdown,
Logger
} from '@nestjs/common';
import { CronJob } from 'cron';
import { Cron as CronJob } from 'croner';
import { v4 } from 'uuid';
import { CronOptions } from './decorators/cron.decorator';
import { SchedulerRegistry } from './scheduler.registry';
Expand All @@ -27,6 +28,8 @@ export class SchedulerOrchestrator
private readonly timeouts: Record<string, TimeoutOptions> = {};
private readonly intervals: Record<string, IntervalOptions> = {};

private readonly logger = new Logger(SchedulerRegistry.name);

constructor(private readonly schedulerRegistry: SchedulerRegistry) {}

onApplicationBootstrap() {
Expand Down Expand Up @@ -67,23 +70,24 @@ export class SchedulerOrchestrator
const cronKeys = Object.keys(this.cronJobs);
cronKeys.forEach((key) => {
const { options, target } = this.cronJobs[key];
const cronJob = new CronJob(
const cronJob = CronJob(
options.cronTime,
target as any,
undefined,
false,
options.timeZone,
undefined,
false,
options.utcOffset,
options.unrefTimeout,
{
timezone: options.timeZone,
unref: options.unrefTimeout,
utcOffset: options.utcOffset,
context: options.context,
interval: options.interval,
protect: options.preventOverrun,
maxRuns: options.maxRuns,
legacyMode: options.legacyMode,
paused: options.disabled,
catch: async (error) => {
this.logger.error(error)
}
},
target as any
);

if (options.disabled) {
cronJob.stop();
} else {
cronJob.start();
}

this.cronJobs[key].ref = cronJob;
this.schedulerRegistry.addCronJob(key, cronJob);
Expand Down
17 changes: 2 additions & 15 deletions lib/scheduler.registry.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import { Injectable, Logger } from '@nestjs/common';
import { CronJob } from 'cron';
import { Injectable } from '@nestjs/common';
import { Cron as CronJob } from 'croner';
import { DUPLICATE_SCHEDULER, NO_SCHEDULER_FOUND } from './schedule.messages';

@Injectable()
export class SchedulerRegistry {
private readonly logger = new Logger(SchedulerRegistry.name);

private readonly cronJobs = new Map<string, CronJob>();
private readonly timeouts = new Map<string, any>();
private readonly intervals = new Map<string, any>();
Expand Down Expand Up @@ -52,8 +50,6 @@ export class SchedulerRegistry {
if (ref) {
throw new Error(DUPLICATE_SCHEDULER('Cron Job', name));
}

job.fireOnTick = this.wrapFunctionInTryCatchBlocks(job.fireOnTick, job);
this.cronJobs.set(name, job);
}

Expand Down Expand Up @@ -103,13 +99,4 @@ export class SchedulerRegistry {
this.timeouts.delete(name);
}

private wrapFunctionInTryCatchBlocks(methodRef: Function, instance: object): Function {
return async (...args: unknown[]) => {
try {
await methodRef.call(instance, ...args);
} catch (error) {
this.logger.error(error);
}
};
}
}
Loading