NestJS میں مقررہ خودکاری
بیک اینڈ نظام بہتر بنانا: Nest.js مائیکرو سروس میں CRON جاب کا استعمال
مقررہ وقت پر چلنے والی NestJS مائیکرو سروس نے فلیٹ کے مقامات کی بار بار آنے والی درخواستوں کو سرور سائیڈ جاب میں یکجا کیا، جو کہیں زیادہ کلائنٹ لوڈ کے لیے ڈیزائن کی گئی تھی۔
پڑھنے کا وقت: 9 منٹتحریر Abdullah Raheel
پس منظر: فلیٹ کے مقامات کا بیک اینڈ
بیک اینڈ کاروباروں کے لیے ٹرک انتظام کی ایپ چلاتا تھا۔ ہر کاروبار کئی ڈرائیورز سنبھالتا اور ٹرکس کے مقامات جاننا چاہتا تھا، اس لیے ڈرائیور کلائنٹس مقررہ وقفوں سے مقام کی تازہ معلومات بھیجتے، جبکہ کاروباری اور منتظم کلائنٹس وہ ڈیٹا استعمال کرتے تھے۔
ابتدائی بیک اینڈ سادہ تھا کیونکہ صارفین کی سرگرمی کم تھی۔ ساخت کا مسئلہ تب سامنے آیا جب اسی API کو روزانہ تقریباً 10,000 فعال صارفین کے متوقع بوجھ اور تیزی سے بڑھتی مقام کی تاریخ سنبھالنی تھی۔
لوکیشن اپ ڈیٹ اینڈ پوائنٹ رکاوٹ بن گیا
افقی اسکیلنگ اور لوڈ بیلنسر آنے والی درخواستیں بانٹ سکتے تھے، مگر لوکیشن اپ ڈیٹ اینڈ پوائنٹ کے اندر کا کام ختم نہیں کرتے تھے۔ ہر ڈرائیور پانچ دن کی ونڈو میں 1,440 پوائنٹس رکھ سکتا تھا: ہر گھنٹے 12، ہر دن 288، اور ہر پوائنٹ کے درمیان پانچ منٹ۔
صف کو ترتیب میں رکھنے کے لیے یا shift کے بعد push، یعنی O(n) + O(1) کام، یا pop کے بعد unshift، یعنی O(1) + O(n) کام درکار تھا۔ صف سنبھالنے کے علاوہ ہر تازہ کاری میں وقت کا حساب، مختصات کی جانچ، ڈیٹا توثیق اور ڈیٹا بیس میں مستقل ذخیرہ بھی شامل تھا۔
ڈرائیور کلائنٹس قابلِ اعتماد گھڑی نہیں تھے۔ کوئی آلہ پانچ منٹ کے ایک وقفے میں پانچ درخواستیں بھیج سکتا تھا، یا نیٹ ورک کوریج سے محروم علاقے میں ایک بھی درخواست نہ بھیج پاتا۔ درخواستوں کی تعداد اور صف پر ہونے والا کام دونوں فعال ڈرائیورز کی تعداد کے ساتھ بڑھتے تھے۔
صرف 1,000 کلائنٹس اگر فی منٹ ایک درخواست کرتے تو مونولتھ کو ہر منٹ 1,000 اور روزانہ تقریباً 1.4 ملین درخواستیں ملتیں۔
تصدیق کو ڈیٹا بیس انضمام سے الگ کریں
ساخت نے ڈیٹا وصول کرنے اور تصدیق کو مرکزی ڈیٹا بیس میں انضمام سے الگ کیا۔ خودکاری خدمت نے مقام کا ڈیٹا جمع کیا اور ہر ٹرک کی زیرِ التوا تازہ کاریاں قابو شدہ حد پر مونولتھ تک پہنچانے کی ذمہ داری لی۔
کرون جاب ہر پانچ منٹ بعد چلی اور مقامات کی صفوں والی ایک یکجا درخواست بھیجی۔ قابلِ پیمائش تبدیلی ڈیٹا بیس کی ثابت شدہ رفتار نہیں، درخواست کی شکل تھی: بہت سی کلائنٹ تحریریں ہر شیڈیولر انسٹینس سے پانچ منٹ میں ایک بیچ درخواست بن گئیں۔
یہی مائیکرو سروس آنے والی API کالز بھی سنتی اور تجزیاتی معلومات واپس کرسکتی تھی، جبکہ مقررہ حد طے کرتی تھی کہ جمع شدہ ڈیٹا مونولتھ تک کب پہنچے۔
NestJS مائیکرو سروس بنائیں
Nest CLI نصب کریں، منصوبہ بنائیں، اور سرکاری مائیکرو سروسز، نظام الاوقات اور HTTP پیکیجز شامل کریں۔
npm i -g @nestjs/cli
nest new project-name
# Or create the project in the current directory:
nest new .
npm i --save @nestjs/microservices
npm install --save @nestjs/schedule
npm install --save-dev @types/cron
npm i --save @nestjs/axios axiosنیچے دیا آغاز عام HTTP سرور کو پورٹ 8080 پر چلاتا اور TCP مائیکرو سروس کو پورٹ 8081 پر جوڑتا ہے۔ جس خدمت کو HTTP درکار نہ ہو وہ HTTP سننے والا عمل چھوڑ سکتی ہے۔
import { NestFactory } from '@nestjs/core'
import { AppModule } from './app.module'
import { Transport } from '@nestjs/microservices'
async function bootstrap() {
const app = await NestFactory.create(AppModule)
app.connectMicroservice({
transport: Transport.TCP,
options: {
port: 8081
}
})
await app.startAllMicroservices()
await app.listen(8080)
}
bootstrap()AppModule مقام اور شیڈیولر ماڈیولز کو جوڑتا ہے تاکہ آنے والے مقامات کی پروسیسنگ اور شیڈیولڈ پرسسٹنس الگ رہیں۔
import { Module } from '@nestjs/common'
import { LocationModule } from './location/location.module'
import { SchedulerModule } from './scheduler/scheduler.module'
@Module({
imports: [SchedulerModule, LocationModule],
providers: []
})
export class AppModule {}کرون جاب کو الگ ماڈیول میں رکھیں
مقام ماڈیول اپنے کنٹرولر اور خدمت کا مالک ہے۔ کنٹرولر آنے والی GET درخواستیں اور location_updated واقعات سنبھالتا ہے، جبکہ خدمت مقام کے عمل چلا یا واقعات کے جواب میں متحرک جابز بنا سکتی ہے۔
نظام الاوقات الگ ماڈیول میں رہتا ہے تاکہ Nest غیر ضروری دہرائی ہوئی جابز درج نہ کرے۔ مقام خدمت بھی ایک مشترک پرووائیڈر ہونی چاہیے۔ SchedulerModule کے اندر LocationService دوبارہ دینے سے نئی Nest انسٹینس بنے گی اور شیڈیولر، کنٹرولر سے مختلف عارضی یادداشت کا بفر پڑھ سکتا ہے۔
import { Module } from '@nestjs/common'
import { ScheduleModule } from '@nestjs/schedule'
import { HttpModule } from '@nestjs/axios'
import { LocationModule } from '../location/location.module'
import { SchedulerService } from './scheduler.service'
@Module({
imports: [ScheduleModule.forRoot(), HttpModule, LocationModule],
providers: [SchedulerService]
})
export class SchedulerModule {}یکجا تازہ کاری مقرر کرکے بھیجیں
شیڈیولر، CronExpression.EVERY_5_MINUTES استعمال کرتا ہے۔ HttpService ایک Observable واپس کرتا ہے، اس لیے firstValueFrom، PATCH درخواست مکمل کرتا ہے۔ اگلے طریقے فرضی کوڈ ہیں: peek حذف کیے بغیر پڑھتا، اور acknowledge صرف وہ بیچ ہٹاتا ہے جس کی مونولتھ تصدیق کرے۔ 2023 نمونے میں مستقل وصولی کی تصدیق نافذ نہیں تھی۔
import { HttpService } from '@nestjs/axios'
import { Injectable } from '@nestjs/common'
import { Cron, CronExpression } from '@nestjs/schedule'
import { firstValueFrom } from 'rxjs'
import { externalLinks } from 'src/links'
import { LocationService } from 'src/location/location.service'
@Injectable()
export class SchedulerService {
constructor(
private readonly locationService: LocationService,
private readonly httpService: HttpService
) {}
@Cron(CronExpression.EVERY_5_MINUTES)
async locationBulkUpdateJob() {
const batch = this.locationService.peekPendingLocations()
if (batch.length === 0) return
await firstValueFrom(
this.httpService.patch(externalLinks.backendProdLink, { locations: batch })
)
this.locationService.acknowledgeLocations(batch)
}
}- RxJS غیر ہم وقت جواب اور نقص کے راستے کے لیے Observables اور آپریٹرز دیتا ہے۔
- @nestjs/schedule، کرون جاب درج کرتا اور EVERY_5_MINUTES جیسے پہلے سے متعین اظہارات دیتا ہے، جو */5 * * * * کے برابر ہے۔
- @nestjs/axios، مونولتھ کو PATCH درخواست بھیجنے کے لیے Nest کے HttpService کے ذریعے Axios دیتا ہے۔
وہ مسائل جو نمونہ حل نہیں کرتا
کرون ڈیکوریٹر صرف کام کا وقت مقرر کرتا ہے۔ یہ ایک ہی کام کے دہرے اجرا کو نہیں روکتا، دوبارہ آغاز کے بعد بفر شدہ ڈیٹا محفوظ نہیں رکھتا، اور نہ ہی یہ ضمانت دیتا ہے کہ شیڈیول چلانے کی ذمہ داری صرف ایک ریپلیکا کے پاس ہوگی۔
- زیرِ التوا مقامات مستقل محفوظ کریں تاکہ دوبارہ آغاز وقفے کا ڈیٹا نہ مٹا سکے۔
- آئیڈیم پوٹینسی یا بیچ کلید لگائیں تاکہ دوبارہ کوشش ایک ہی مقامات دو بار نہ لکھے۔
- بیچ صرف مونولتھ کی تصدیق کے بعد قبول کریں؛ وقت ختم ہونے یا ناکامی پر اسے برقرار رکھیں۔
- جب ایک PATCH پانچ منٹ سے زیادہ لے تو رنز کو ایک دوسرے پر چڑھنے سے روکیں۔
- بیچ کی حد مقرر کریں اور جب ڈیٹا وصولی، انضمام سے تیز ہو تو پس دباؤ طے کریں۔
- نظام الاوقات کو ایک منتخب ورکر، تقسیم شدہ قفل یا بیرونی شیڈیولر سے چلائیں۔ ورنہ ہر ایپ نقل وہی کرون جاب درج کرتی ہے۔
نتیجہ اور حوالہ جات
شیڈیولر آلات سے ڈیٹا لکھنے کی متعدد درخواستوں کو ہر پانچ منٹ بعد ایک بیچ میں بدلتا ہے۔ یہ کام کی جانچ، دوبارہ کوشش اور تصدیق کے لیے ایک جگہ فراہم کرتا ہے، مگر میرے پاس ڈیٹا بیس کے بوجھ، اپ ٹائم یا ڈیلیوری ریٹ کے پروڈکشن اعداد نہیں ہیں۔
- اصل مسئلے میں بڑھتی کلائنٹ آمدورفت کے ساتھ مہنگا ہوتا لوکیشن اپ ڈیٹ اینڈ پوائنٹ شامل تھا۔
- الگ خودکاری مائیکرو سروس نے یکجا مقام تازہ کاریاں مونولتھ کو بھیجنے کی ذمہ داری لی۔
- کرون جاب ہر پانچ منٹ بعد چلتی اور زیرِ التوا مقامات کو ایک درخواست میں یکجا کرتی ہے۔
- اطلاق، NestJS مائیکرو سروسز، کام کا نظام الاوقات، HTTP ماڈیول اور RxJS استعمال کرتا ہے۔

