คุณเคยเจอสถานการณ์ที่คุณต้องกำหนดเวลางานหรือสร้างงานที่เกิดซ้ำใน NodeJS หรือไม่? ถ้าใช่ คุณอาจนึกถึงเมธอด setInterval ของ JavaScript แล้ว หรือคุณอาจใช้แพ็คเกจ npm เช่น cron หรือ node-schedule

พวกเขาจะทำงานหากมีเซิร์ฟเวอร์เพียงอินสแตนซ์เดียวที่ทำงานอยู่ แต่จะเกิดอะไรขึ้นหากคุณกำลังออกแบบระบบที่ต้องการความพร้อมใช้งานสูงและเพื่อการนั้น คุณจึงมีเซิร์ฟเวอร์หลายอินสแตนซ์ที่ทำงานอยู่ จากนั้นวิธีการดังกล่าวจะมีปัญหาเกิดขึ้นพร้อมกัน ซึ่งอาจทำให้งานเดียวกันถูกจัดกำหนดการหลายครั้งเมื่อเซิร์ฟเวอร์หลายเครื่องเริ่มทำงาน
นอกจากนี้ยังจะเป็นเรื่องยากในการจัดการกับข้อผิดพลาดสำหรับงานที่ล้มเหลวในกรณีนี้

การทำงานพร้อมกันเป็นเหตุผลหลักที่ทำให้ฉันเริ่มมองหาวิธีแก้ปัญหาอื่นๆ และ Queues ก็เข้ามาช่วยเหลือฉัน

สามารถใช้คิวได้สามวิธี —
1. Job Producer
2. Job Consumer
3. Event Listener

ผู้ผลิตจะเพิ่มงานในคิว ผู้บริโภค/พนักงานจะทำงาน และผู้ฟังเหตุการณ์จะรับฟังเหตุการณ์ที่เกิดขึ้นในคิวนั้น
อินสแตนซ์หนึ่งของคิวสามารถใช้สำหรับทั้งสามบทบาท และผู้ผลิตหลายราย ผู้บริโภคและผู้ฟังสามารถใช้คิวเดียวกันได้ในเวลาเดียวกัน
เนื่องจาก Queues ใช้ Redis ในการสื่อสารระหว่างผู้ผลิตและผู้บริโภค จึงช่วยแก้ปัญหาแรกของเราเรื่องการทำงานพร้อมกันได้ หากผู้ผลิตและผู้บริโภคสามารถเชื่อมต่อกับ Redis ได้ พวกเขาก็จะสามารถทำงานร่วมกันในขณะที่ประมวลผลงานได้
คิวยังมีการสื่อสารแบบอะซิงโครนัส เนื่องจากคิวไม่ปิดกั้นโค้ด

ข้อมูลเบื้องต้นเกี่ยวกับคิวกระทิง

Bull เป็นไลบรารี Node ที่ใช้ Queues โดยอิงจาก Redis แม้ว่าคิวจะสามารถนำมาใช้โดยตรงใน Redis ได้ แต่ไลบรารีนี้จะจัดการโค้ดระดับต่ำทั้งหมด
การใช้ Bull ยังช่วยแก้ปัญหาการจัดการข้อผิดพลาดเนื่องจากมีกลไก RETRY เราสามารถผ่านจำนวนครั้งที่เราต้องการได้งานได้

Bull เพิ่มเฉพาะงานที่ไม่ซ้ำใครในคิวเท่านั้น ดังนั้นจึงช่วยแก้ปัญหางานเดียวกันที่ถูกกำหนดเวลาไว้หลายครั้งได้

ลองยกตัวอย่างง่ายๆ สมมติว่าคุณต้องการพิมพ์จำนวนผู้ใช้ทั้งหมดที่อยู่ใน DB ของคุณทุกๆ 10 นาที เราจะดำเนินการนี้โดยใช้ไลบรารี Bull

การใช้ไลบรารี Bull-

npm install bull

ตอนนี้ให้สร้างไฟล์ใหม่ app.js และนำเข้าไลบรารี่กระทิงในไฟล์นั้น

const Queue = require(‘bull’);

เราต้องกำหนดการกำหนดค่า Redis ในกรณีที่เราใช้การกำหนดค่าแบบกำหนดเอง

let redisConf = {
    host: 127.0.0.1, 
    port: 6379, 
    username: USERNAME, 
    password: PASSWORD
};

สร้างคิวใหม่ด้วยการกำหนดค่า Redis ที่กำหนดเอง

let queue = new Queue(‘myQueue’, {redis: redisConf} );
// Where ‘myQueue’ is the name of Queue.

บทบาทของโปรดิวเซอร์คือการผลิตงาน เช่น สร้างตารางเวลา กำหนดการอาจเป็นแบบครั้งเดียวหรือเกิดซ้ำก็ได้ เราสามารถมีตารางเวลาได้ทั้งสองประเภทใน Bull เรากำลังยกตัวอย่างกำหนดการที่เกิดซ้ำในโพสต์นี้

เนื่องจากเราต้องการกำหนดเวลางานเป็นเวลา 10 นาที เราจึงต้องประกาศการหมดเวลาสำหรับสิ่งนั้น

let timeout = 600000; // Time is in milliseconds
let data = {key: value};
queue.add(data, {repeat: {every: timeout} } );
//Where data is an object. 
//It can be an empty object also. 
//The value of data can be used while consuming the job. 

บทบาทของผู้บริโภคคือการบริโภคงานหรืองาน queue.process() จะถูกเรียกทุกครั้งที่มีงานอยู่ในคิว เนื่องจากเรามีงานที่เกิดซ้ำ 10 นาที ฟังก์ชันกระบวนการจะถูกเรียกทุกๆ 10 นาที

queue.process(async (job) => {
    let data = job.data;
    /* using job.data, the data object can be used which was passed   
    while creating the job */
    /* we want to print count of all user after every 10 minutes */
    let count = await db.countUsersDummyFunc();
    console.log(count);
});

เมื่องานได้รับการประมวลผลแล้ว สถานะของงานจะเปลี่ยนเป็นเสร็จสมบูรณ์ เราสามารถใช้บทบาท Event Listener ของ Queue และฟังเหตุการณ์ 'เสร็จสมบูรณ์' ได้

queue.on('completed', async (job) => {
    console.log(`Job ${job.id}` completed`);
    /* Completed jobs will remain in Redis. It may cause unnecesarry memory utilization. For this we have the option to remove the job. */
    await job.remove();
});

เราได้พูดคุยถึงบทบาททั้งสามของ Queues ในโพสต์นี้ เราเริ่มต้นด้วยการเพิ่มงานในคิว (บทบาทผู้ผลิต) จากนั้นจึงประมวลผลงานนั้นตามช่วงเวลาปกติ (Consumer Role) และในตอนท้าย เราได้ฟังเหตุการณ์ใน Queue (Event Listener Role)
เรายังไม่ได้พูดคุยถึงวิธีจัดการกับงานที่ล้มเหลวและเพิ่มการลองใหม่ในงาน อาจเป็นส่วนหนึ่งของโพสต์ถัดไปของฉัน

ขอบคุณที่อ่านเรื่องนี้ ขอให้มีวันดีๆ ข้างหน้า