项目开发需求定时发送邮件任务,要求发送时间为截止日期的前一周,前一天,后一天和后一周这四个时间点。当事务完成后中断定时任务。 在 NestJS 中,可以使用 SchedulerRegistry 来动态创建和管理定时任务。 首先在 task.service.ts 文件中引入 @nestjs/schedule, 并注册 SchedulerRegistry
import { Cron, SchedulerRegistry } from '@nestjs/schedule';
@Injectable()
export class TasksService {
constructor(
private readonly schedulerRegistry: SchedulerRegistry
) { }
}
然后在 TasksService 中定义方法,代码如下:
// 创建任务
async createBeforeTask(action: CallReportAction, message: Message, name: string) {
let job: CronJob
for (const key of getCronExpression(action.deadline)) {
job = new CronJob(key, () => {
this.messageService.sendActionEmail(action, message)
});
this.schedulerRegistry.addCronJob(name + Math.random(), job);
job.start();
}
}
/**
* 定时邮件计算出定时时间
* @param time
* @returns Date[]
*/
export const getCronExpression = (time: Date): Date[] => {
const Dates = [];
var previousDay = moment(time).subtract(1, 'days').startOf('day').toDate()
var previousWeek = moment(time).subtract(7, 'days').startOf('day').toDate()
var afterDay = moment(time).add(1, 'days').startOf('day').toDate()
var afterWeek = moment(time).add(7, 'days').startOf('day').toDate()
if (new Date(previousDay) > new Date()) {
Dates.push(previousDay)
}
if (new Date(previousWeek) > new Date()) {
Dates.push(previousWeek)
}
if (new Date(afterWeek) > new Date()) {
Dates.push(afterWeek)
}
if (new Date(afterDay) > new Date()) {
Dates.push(afterDay)
}
return Dates;
}
// 关闭任务
deleteTask(name: string): void {
const tasks = this.schedulerRegistry.getCronJobs();
for (const [key, value] of tasks) {
if (key.includes(name)) {
this.schedulerRegistry.deleteCronJob(key);
// 这里可以添加日志记录,或者其他逻辑
}
}
}
createBeforeTask 用于动态发起定时任务,name 代表要开启的任务名。getCronExpression 方法计算定时发送的四个时间点。循环遍历四个时间点依次添加定时任务。deleteTask 是用于中断定时任务,接收参数只需要任务名即可。 然后在需要调用方法的地方引入即可,代码如下:
// 引入 TaskServivce
import { TasksService } from '@/modules/tasks/tasks.service';
export class TimedTransmissionProcessor {
constructor(
private readonly tasksService: TasksService
) { }
async action(job: Job<any>) {
try {
const { newAction, message } = job.data
// 定义任务名,且具有唯一性
const name = 'action' + newAction?.id.toString() + '_'
// 删除存在的同名任务
this.tasksService.deleteTask(name)
// 开启定时任务
await this.tasksService.createBeforeTask(newAction, message, name)
} catch (error) {
Logger.log(error)
throw error
}
}
}
这样就可以实现动态定时任务的开启和关闭的功能。