Task scheduling
Task scheduling sizga istalgan kodni (metod/funksiyalarni) belgilangan sana/vaqtda, qayta takrorlanuvchi intervalda yoki ko'rsatilgan intervaldan so'ng bir marta bajarishni rejalas
Task scheduling sizga istalgan kodni (metod/funksiyalarni) belgilangan sana/vaqtda, qayta takrorlanuvchi intervalda yoki ko'rsatilgan intervaldan so'ng bir marta bajarishni rejalashtirish imkonini beradi. Linux olamida bu odatda OS darajasida cron kabi paketlar bilan bajariladi. Node.js ilovalari uchun cron ga o'xshash funksionallikni emulyatsiya qiladigan bir nechta paketlar mavjud. Nest @nestjs/schedule paketini taqdim etadi, u mashhur Node.js cron paketi bilan integratsiya qiladi. Ushbu bobda aynan shu paketni ko'rib chiqamiz.
O'rnatish
Uni ishlatishni boshlash uchun avvalo kerakli bog'liqliklarni o'rnatamiz.
1$ npm install --save @nestjs/scheduleJob schedulingni yoqish uchun ScheduleModule ni root AppModule ga import qiling va quyida ko'rsatilgandek forRoot() statik metodini ishga tushiring:
1import { Module } from '@nestjs/common';
2import { ScheduleModule } from '@nestjs/schedule';
3
4@Module({
5 imports: [
6 ScheduleModule.forRoot()
7 ],
8})
9export class AppModule {}.forRoot() chaqiruvi scheduler'ni inicializatsiya qiladi va ilovangizda mavjud bo'lgan deklarativ cron joblar, timeoutlar va intervallarni ro'yxatdan o'tkazadi. Ro'yxatdan o'tkazish onApplicationBootstrap lifecycle hook sodir bo'lganda amalga oshadi, bu esa barcha modullar yuklanganini va rejalashtirilgan ishlarni e'lon qilganini ta'minlaydi.
Deklarativ cron job'lar
Cron job istalgan funksiyani (metod chaqiruvini) avtomatik bajarishga rejalashtiradi. Cron job'lar quyidagicha ishlashi mumkin:
- Bir marta, belgilangan sana/vaqtda.
- Qayta takrorlanuvchi asosda; takrorlanuvchi ishlar belgilangan interval ichida ma'lum bir vaqtda ishlashi mumkin (masalan, soatiga bir marta, haftasiga bir marta, har 5 daqiqada bir marta)
Cron job'ni @Cron() dekoratorini bajariladigan kod joylashgan metoddan oldin qo'yish orqali e'lon qiling, quyidagicha:
1import { Injectable, Logger } from '@nestjs/common';
2import { Cron } from '@nestjs/schedule';
3
4@Injectable()
5export class TasksService {
6 private readonly logger = new Logger(TasksService.name);
7
8 @Cron('45 * * * * *')
9 handleCron() {
10 this.logger.debug('Called when the current second is 45');
11 }
12}Ushbu misolda handleCron() metodi joriy soniya 45 bo'lganda chaqiriladi. Boshqacha aytganda, metod har daqiqada bir marta, 45-soniyada ishga tushadi.
@Cron() dekoratori quyidagi standart cron patternlarni qo'llab-quvvatlaydi:
- Asterisk (masalan,
*) - Ranges (masalan,
1-3,5) - Steps (masalan,
*/2)
Yuqoridagi misolda dekoratorga 45 * * * * * ni uzatdik. Quyidagi kalit cron pattern satridagi har bir pozitsiya qanday talqin qilinishini ko'rsatadi:
1* * * * * *
2| | | | | |
3| | | | | day of week
4| | | | months
5| | | day of month
6| | hours
7| minutes
8seconds (optional)Ba'zi cron pattern namunalari:
* * * * * * | har soniyada |
45 * * * * * | har daqiqada, 45-soniyada |
0 10 * * * * | har soatda, 10-daqiqa boshida |
0 */30 9-17 * * * | 09:00 dan 17:00 gacha har 30 daqiqada |
0 30 11 * * 1-5 | Monday to Friday at 11:30am |
@nestjs/schedule paketi ko'p ishlatiladigan cron patternlar uchun qulay enum taqdim etadi. Bu enumdan quyidagicha foydalanishingiz mumkin:
1import { Injectable, Logger } from '@nestjs/common';
2import { Cron, CronExpression } from '@nestjs/schedule';
3
4@Injectable()
5export class TasksService {
6 private readonly logger = new Logger(TasksService.name);
7
8 @Cron(CronExpression.EVERY_30_SECONDS)
9 handleCron() {
10 this.logger.debug('Called every 30 seconds');
11 }
12}Ushbu misolda handleCron() metodi har 30 soniyada chaqiriladi. Agar istisno yuzaga kelsa, u konsolga loglanadi, chunki @Cron() bilan belgilangan har bir metod avtomatik ravishda try-catch blokiga o'raladi.
Muqobil ravishda, @Cron() dekoratoriga JavaScript Date obyektini uzatishingiz mumkin. Bunda job ko'rsatilgan sanada aniq bir marta ishlaydi.
Joriy sanaga nisbatan job rejalashtirish uchun JavaScript date arithmetic'dan foydalaning. Masalan, @Cron(new Date(Date.now() + 10 * 1000)) ilova ishga tushganidan 10 soniya o'tib ishga tushadigan jobni rejalashtiradi.
Shuningdek, @Cron() dekoratoriga ikkinchi parametr sifatida qo'shimcha opsiyalarni uzatishingiz mumkin.
name | E'lon qilingandan so'ng cron jobga kirish va uni boshqarish uchun foydali. |
timeZone | Bajarilish uchun vaqt zonasini ko'rsating. Bu haqiqiy vaqtni sizning time zone'ingizga nisbatan o'zgartiradi. Agar time zone noto'g'ri bo'lsa, xato tashlanadi. Mavjud barcha time zonalarni Moment Timezone saytida tekshirishingiz mumkin. |
utcOffset | Bu `timeZone` parametri o'rniga time zone offsetini ko'rsatish imkonini beradi. |
waitForCompletion |
Agar true bo'lsa, joriy onTick callback tugamaguncha cron jobning qo'shimcha instansiyalari ishga tushmaydi. Joriy cron job ishlayotganda rejalashtirilgan yangi bajarilishlar butunlay o'tkazib yuboriladi.
|
disabled | Bu job umuman bajariladimi-yo'qligini bildiradi. |
1import { Injectable } from '@nestjs/common';
2import { Cron, CronExpression } from '@nestjs/schedule';
3
4@Injectable()
5export class NotificationService {
6 @Cron('* * 0 * * *', {
7 name: 'notifications',
8 timeZone: 'Europe/Paris',
9 })
10 triggerNotifications() {}
11}E'lon qilingandan so'ng cron jobga kirish va uni boshqarish yoki cron patterni runtime paytida aniqlanadigan dinamik cron job yaratish uchun Dynamic API dan foydalanishingiz mumkin. API orqali deklarativ cron jobga kirish uchun dekoratorning ikkinchi argumenti sifatidagi ixtiyoriy opsiyalar obyektida name xossasini berib, jobga nom biriktirishingiz kerak.
Deklarativ interval'lar
Metod belgilangan (takrorlanuvchi) intervalda ishlashi kerakligini e'lon qilish uchun metod ta'rifidan oldin @Interval() dekoratorini qo'ying. Decoratorga millisekundlarda interval qiymatini uzating, quyidagicha:
1@Interval(10000)
2handleInterval() {
3 this.logger.debug('Called every 10 seconds');
4}Bu mexanizm ichkarida JavaScript setInterval() funksiyasidan foydalanadi. Shuningdek, takrorlanuvchi ishlarni rejalashtirish uchun cron job'ni ham ishlatishingiz mumkin.
Agar deklarativ interval'ni e'lon qilgan sinfdan tashqarida Dynamic API orqali boshqarishni xohlasangiz, intervalni quyidagi konstruktsiya bilan nomga bog'lang:
1@Interval('notifications', 2500)
2handleInterval() {}Agar istisno yuzaga kelsa, u konsolga loglanadi, chunki @Interval() bilan belgilangan har bir metod avtomatik ravishda try-catch blokiga o'raladi.
Dynamic API shuningdek runtime paytida interval xossalari aniqlanadigan dinamik interval'larni yaratish, hamda ularni ro'yxatlash va o'chirish imkonini beradi.
Deklarativ timeout'lar
Metod belgilangan timeoutdan keyin bir marta ishlashi kerakligini e'lon qilish uchun metod ta'rifidan oldin @Timeout() dekoratorini qo'ying. Decoratorga ilova ishga tushganidan boshlab millisekundlarda nisbiy vaqt ofsetini uzating, quyidagicha:
1@Timeout(5000)
2handleTimeout() {
3 this.logger.debug('Called once after 5 seconds');
4}Bu mexanizm ichkarida JavaScript setTimeout() funksiyasidan foydalanadi.
Agar istisno yuzaga kelsa, u konsolga loglanadi, chunki @Timeout() bilan belgilangan har bir metod avtomatik ravishda try-catch blokiga o'raladi.
Agar deklarativ timeout'ni e'lon qilgan sinfdan tashqarida Dynamic API orqali boshqarishni xohlasangiz, timeoutni quyidagi konstruktsiya bilan nomga bog'lang:
1@Timeout('notifications', 2500)
2handleTimeout() {}Dynamic API shuningdek runtime paytida timeout xossalari aniqlanadigan dinamik timeout'larni yaratish, hamda ularni ro'yxatlash va o'chirish imkonini beradi.
Dynamic schedule module API
@nestjs/schedule moduli deklarativ cron joblar, timeoutlar va intervallarni boshqarishga imkon beradigan dinamik API taqdim etadi. API shuningdek runtime paytida xossalari aniqlanadigan dinamik cron job'lar, timeout'lar va interval'larni yaratish va boshqarish imkonini beradi.
Dinamik cron job'lar
SchedulerRegistry API yordamida kodingizning istalgan joyidan nomi bo'yicha CronJob instansiyasiga havola oling. Avval SchedulerRegistry ni odatiy konstruktor in'eksiyasi orqali kiriting:
1constructor(private schedulerRegistry: SchedulerRegistry) {}SchedulerRegistry ni @nestjs/schedule paketidan import qiling.
So'ng uni sinfda quyidagicha ishlating. Faraz qilaylik, quyidagi deklaratsiya bilan cron job yaratilgan:
1@Cron('* * 8 * * *', {
2 name: 'notifications',
3})
4triggerNotifications() {}Ushbu jobga quyidagicha kiring:
1const job = this.schedulerRegistry.getCronJob('notifications');
2
3job.stop();
4console.log(job.lastDate());getCronJob() metodi nomlangan cron jobni qaytaradi. Qaytgan CronJob obyektida quyidagi metodlar mavjud:
stop()- rejalashtirilgan jobni to'xtatadi.start()- to'xtatilgan jobni qayta ishga tushiradi.setTime(time: CronTime)- jobni to'xtatadi, yangi vaqt belgilaydi va keyin jobni qayta ishga tushiradi.lastDate()- job oxirgi marta bajarilgan sanaDateTimeko'rinishini qaytaradi.nextDate()- job keyingi marta bajarilishi rejalashtirilgan sananingDateTimeko'rinishini qaytaradi.nextDates(count: number)- job bajarilishini boshlatadigan keyingi sanalar uchunDateTimeko'rinishlaridan iborat massivni (o'lchamicount) qaytaradi.countdefault holatda 0 bo'lib, bo'sh massiv qaytaradi.
DateTime obyektlarini JavaScript Date ekvivalentiga aylantirish uchun toJSDate() dan foydalaning.
SchedulerRegistry#addCronJob metodi yordamida yangi cron jobni dinamik yarating, quyidagicha:
1addCronJob(name: string, seconds: string) {
2 const job = new CronJob(`${seconds} * * * * *`, () => {
3 this.logger.warn(`time (${seconds}) for job ${name} to run!`);
4 });
5
6 this.schedulerRegistry.addCronJob(name, job);
7 job.start();
8
9 this.logger.warn(
10 `job ${name} added for each minute at ${seconds} seconds!`,
11 );
12}Bu kodda biz cron paketidagi CronJob obyektidan foydalanib cron job yaratamiz. CronJob konstruktori birinchi argument sifatida cron patternni (@Cron() dekoratori kabi) va ikkinchi argument sifatida cron taymeri ishga tushganda bajariladigan callbackni oladi. SchedulerRegistry#addCronJob metodi ikki argument qabul qiladi: CronJob uchun nom va CronJob obyektining o'zi.
SchedulerRegistry ga kirishdan oldin uni in'eksiya qilishni unutmang. CronJob ni cron paketidan import qiling.
SchedulerRegistry#deleteCronJob metodi yordamida nomlangan cron jobni o'chiring, quyidagicha:
1deleteCron(name: string) {
2 this.schedulerRegistry.deleteCronJob(name);
3 this.logger.warn(`job ${name} deleted!`);
4}SchedulerRegistry#getCronJobs metodi yordamida barcha cron joblarni ro'yxatlang, quyidagicha:
1getCrons() {
2 const jobs = this.schedulerRegistry.getCronJobs();
3 jobs.forEach((value, key, map) => {
4 let next;
5 try {
6 next = value.nextDate().toJSDate();
7 } catch (e) {
8 next = 'error: next fire date is in the past!';
9 }
10 this.logger.log(`job: ${key} -> next: ${next}`);
11 });
12}getCronJobs() metodi map qaytaradi. Bu kodda biz map bo'ylab iteratsiya qilib, har bir CronJob ning nextDate() metodiga kirishga harakat qilamiz. CronJob APIda agar job allaqachon ishga tushgan bo'lsa va kelajakdagi ishga tushish sanasi bo'lmasa, u istisno tashlaydi.
Dinamik interval'lar
SchedulerRegistry#getInterval metodi yordamida intervalga havola oling. Yuqoridagi kabi, SchedulerRegistry ni odatiy konstruktor in'eksiyasi orqali kiriting:
1constructor(private schedulerRegistry: SchedulerRegistry) {}Va quyidagicha foydalaning:
1const interval = this.schedulerRegistry.getInterval('notifications');
2clearInterval(interval);SchedulerRegistry#addInterval metodi yordamida yangi intervalni dinamik yarating, quyidagicha:
1addInterval(name: string, milliseconds: number) {
2 const callback = () => {
3 this.logger.warn(`Interval ${name} executing at time (${milliseconds})!`);
4 };
5
6 const interval = setInterval(callback, milliseconds);
7 this.schedulerRegistry.addInterval(name, interval);
8}Bu kodda biz standart JavaScript interval yaratamiz, so'ng uni SchedulerRegistry#addInterval metodiga uzatamiz.
Ushbu metod ikki argument qabul qiladi: interval uchun nom va intervalning o'zi.
SchedulerRegistry#deleteInterval metodi yordamida nomlangan intervalni o'chiring, quyidagicha:
1deleteInterval(name: string) {
2 this.schedulerRegistry.deleteInterval(name);
3 this.logger.warn(`Interval ${name} deleted!`);
4}SchedulerRegistry#getIntervals metodi yordamida barcha interval'larni ro'yxatlang, quyidagicha:
1getIntervals() {
2 const intervals = this.schedulerRegistry.getIntervals();
3 intervals.forEach(key => this.logger.log(`Interval: ${key}`));
4}Dinamik timeout'lar
SchedulerRegistry#getTimeout metodi yordamida timeoutga havola oling. Yuqoridagi kabi, SchedulerRegistry ni odatiy konstruktor in'eksiyasi orqali kiriting:
1constructor(private readonly schedulerRegistry: SchedulerRegistry) {}Va quyidagicha foydalaning:
1const timeout = this.schedulerRegistry.getTimeout('notifications');
2clearTimeout(timeout);SchedulerRegistry#addTimeout metodi yordamida yangi timeoutni dinamik yarating, quyidagicha:
1addTimeout(name: string, milliseconds: number) {
2 const callback = () => {
3 this.logger.warn(`Timeout ${name} executing after (${milliseconds})!`);
4 };
5
6 const timeout = setTimeout(callback, milliseconds);
7 this.schedulerRegistry.addTimeout(name, timeout);
8}Bu kodda biz standart JavaScript timeout yaratamiz, so'ng uni SchedulerRegistry#addTimeout metodiga uzatamiz.
Ushbu metod ikki argument qabul qiladi: timeout uchun nom va timeoutning o'zi.
SchedulerRegistry#deleteTimeout metodi yordamida nomlangan timeoutni o'chiring, quyidagicha:
1deleteTimeout(name: string) {
2 this.schedulerRegistry.deleteTimeout(name);
3 this.logger.warn(`Timeout ${name} deleted!`);
4}SchedulerRegistry#getTimeouts metodi yordamida barcha timeout'larni ro'yxatlang, quyidagicha:
1getTimeouts() {
2 const timeouts = this.schedulerRegistry.getTimeouts();
3 timeouts.forEach(key => this.logger.log(`Timeout: ${key}`));
4}Misol
Ishlaydigan misol bu yerda mavjud.