ฉันจะแน่ใจได้อย่างไรว่างานไม่ทำงานสองครั้งใน Bull


11

ฉันมีสองฟังก์ชั่นและscheduleScan()scan()

scan()สายscheduleScan() เมื่อมีอะไรอย่างอื่นทำยกเว้นการจัดตารางการสแกนใหม่เพื่อให้สามารถกำหนดเวลาscheduleScan() scan()แต่มีปัญหาบางงานรันสองครั้ง

ฉันต้องการตรวจสอบให้แน่ใจว่ามีงานเพียงงานเดียวที่ดำเนินการในเวลาใดก็ตาม ฉันจะบรรลุสิ่งนั้นได้อย่างไร ฉันเชื่อว่ามีบางอย่างที่เกี่ยวข้องกับdone()(อยู่ในการสแกน () ลบออกตอนนี้) แต่ฉันไม่สามารถหาวิธีแก้ปัญหาได้

รุ่น Bull: 3.12.1

การแก้ไขล่าช้าที่สำคัญ: scan()เรียกใช้ฟังก์ชั่นอื่นและพวกเขาอาจหรือไม่อาจเรียกฟังก์ชั่นอื่น ๆ แต่พวกเขาทั้งหมดฟังก์ชั่นการซิงค์ดังนั้นพวกเขาจึงเรียกฟังก์ชั่นเฉพาะเมื่องานของตัวเองเสร็จสมบูรณ์มีเพียงข้างเดียว ในตอนท้ายของ "ต้นไม้" ฉันเรียกมันว่าฟังก์ชั่นสุดท้ายเรียก schedScan () แต่ไม่มีงานสองงานพร้อมกันทำงาน ทุกงานเริ่มต้นscan()ตามวิธีและจบด้วยscheduleScan(stock, period, milliseconds, 'called by file.js')

export function update(job) {
  // does some calculations, then it may call scheduleScan() or
  // it may call another function, and that could be the one calling
  // scheduleScan() function.
  // For instance, a function like finalize()
}

export function scan(job) {
  update(job)
}


import moment from 'moment'
import stringHash from 'string-hash'
const opts = { redis: { port: 6379, host: '127.0.0.1', password: mypassword' } }
let queue = new Queue('scan', opts)

queue.process(1, (job) => {
  job.progress(100).then(() => {
    scan(job)
  })
})

export function scheduleScan (stock, period, milliseconds, triggeredBy) {
  let uniqueId = stringHash(stock + ':' + period)

  queue.getJob(uniqueId).then(job => {
    if (!job) {
      if (milliseconds) {
        queue.add({ stock, period, triggeredBy }, { delay: milliseconds, jobId: uniqueId }).then(() => {
          // console.log('Added with ms: ' + stock + ' ' + period)
        }).catch(err => {
          if (err) {
            console.log('Can not add because it exists ' + new Date())
          }
        })
      } else {
        queue.add({ stock, period, triggeredBy }, { jobId: uniqueId }).then(() => {
          // console.log('Added without ms: ' + stock + ' ' + period)
        }).catch(err => {
          if (err) {
            console.log('Can not add because it exists ' + new Date())
          }
        })
      }
    } else {
      job.getState().then(state => {
        if (state === 'completed') {
          job.remove().then(() => {
            if (milliseconds) {
              queue.add({ stock, period, triggeredBy }, { delay: milliseconds, jobId: uniqueId }).then(() => {
                // console.log('Added with ms: ' + stock + ' ' + period)
              }).catch(err => {
                if (err) {
                  console.log('Can not add because it exists ' + new Date())
                }
              })
            } else {
              queue.add({ stock, period, triggeredBy }, { jobId: uniqueId }).then(() => {
                // console.log('Added without ms: ' + stock + ' ' + period)
              }).catch(err => {
                if (err) {
                  console.log('Can not add because it exists ' + new Date())
                }
              })
            }
          }).catch(err => {
            if (err) {
              // console.log(err)
            }
          })
        }
      }).catch(err => {
        // console.log(err)
      })
    }
  })
}

ฉันไม่สามารถหาscanฟังก์ชั่นคุณสามารถช่วยได้ไหม?
Muhammad Zeeshan

@MuhammadZeeshan ฉันเพิ่มเข้าไปแล้วความผิดของฉัน
salep

คำตอบ:


6

ฉันเชื่อว่าปัญหาของคุณscanคือฟังก์ชั่น async ดังนั้นjob.progressฟังก์ชั่นของคุณจึงโทรออกscanแล้วโทรออกทันทีdoneเพื่อให้คิวประมวลผลงานอื่น

วิธีแก้ปัญหาอาจส่งผ่านการdoneติดต่อกลับเป็นพารามิเตอร์ไปยังscanและscheduleScanฟังก์ชั่นของคุณและเรียกใช้เมื่อคุณเสร็จงานของคุณ (หรือผิดพลาด)

อื่น ๆ (ดีกว่า) วิธีการแก้ปัญหาที่อาจจะให้แน่ใจว่าคุณมักจะกลับมาPromiseจากscanและแล้วรอสัญญาว่าจะแก้ปัญหาและเรียกร้องแล้วscheduleScan doneหากทำสิ่งนี้ตรวจสอบให้แน่ใจว่าคุณเชื่อมโยงสัญญาทั้งหมดของคุณคืนในscheduleScanฟังก์ชันของคุณ

queue.process(1, (job, done) => {
  job.progress(100).then(() => {
    scan(job)
        .then(done)
        .catch(done)
  })
})

export function scan() {
   // business logic
   return scheduleScan()
}

// Chain all of your promise returns. Otherwise
// the scan function will return sooner and allow done to be called
// prior to the scheduleScan function finishing it's execution
export function scheduleScan() {
    return queue.getJob(..).then(() => {
        ....
        return queue.add()...
        ....
        return queue.add(...)
            .catch(e => {
                 console.log(e);
                 // propogate errors!
                 throw e;
             })

}

ฉันได้แก้ไขคำถามแล้วคุณช่วยลองดูอีกครั้งได้ไหมโดยเฉพาะส่วน "การแก้ไขล่าช้าที่สำคัญ"? คำตอบของคุณยังคงใช้ในสถานการณ์นี้หรือไม่? ขอบคุณ
salep

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

อีกครั้งความผิดพลาดของฉัน ฟังก์ชันแรกคือ update () กำลังสแกน แต่ update () อาจเรียกใช้ฟังก์ชันอื่นเช่น finalize () และ finalize () อาจเรียก schedScan () โปรดทราบว่าสิ่งเหล่านี้เกิดขึ้นตามลำดับดังนั้นจึงไม่มีการโทรหลายครั้งฉันกำลังทำสิ่งนี้เพื่อรักษาแอพของฉันแบบแยกส่วน - ขอบคุณ
salep

1
ใช่คำตอบเดียวกัน หากมีการupdateโทรscheduledScanหรือฟังก์ชั่นใด ๆ ระหว่างพวกเขา จุดสำคัญคือคุณต้องคืนเชนสัญญาจากscheduleScanตลอดทางกลับไปยังscanฟังก์ชั่น ดังนั้นหากการscanโทรupdateที่โทรfinalise..... ซึ่งโทรไปscheduleScanยังเชนสัญญาจะต้องส่งคืนผ่านการเรียกใช้ฟังก์ชันทั้งหมดเช่นเพียงแค่ให้แน่ใจว่าคุณส่งคืนสัญญาจากแต่ละฟังก์ชั่นเหล่านี้
jeeves

ดังนั้นเพียงเพื่อชี้แจงความคิดเห็นล่าสุดของฉัน ตัวอย่างเช่นหากภายในสแกนคุณเรียกการปรับปรุง คุณต้องส่งคืนผลลัพธ์ของการอัพเดต (สัญญา) จากฟังก์ชั่นสแกน
jeeves

4

ฟังก์ชั่นสแกนเป็นฟังก์ชั่นอะซิงโครนัส ในqueue.process()ฟังก์ชั่นของคุณคุณจะต้องรอฟังก์ชั่นสแกนแล้วโทรdone()กลับ

export async function scan(job) {
  // it does some calculations, then it creates a new schedule.
  return scheduleScan(stock, period, milliseconds, "scan.js");
}

queue.process(1, (job, done) => {
  job.progress(100).then(async() => {
    await scan(job);
    done();
  });
});

export async function scheduleScan(stock, period, milliseconds, triggeredBy) {
    let uniqueId = stringHash(stock + ":" + period);
    try {
      const existingJob = await queue.getJob(uniqueId);
      if (!existingJob) {
        const job = await addJob({
          queue,
          stock,
          period,
          uniqueId,
          milliseconds,
          triggeredBy
        });
        return job;
      } else {
        const jobState = await existingJob.getState();
        if (jobState === "completed") {
          await existingJob.remove();
          const newJob = await addJob({
            queue,
            stock,
            period,
            uniqueId,
            milliseconds,
            triggeredBy
          });
          return newJob;
        }
      }
    } catch (err) {
      throw new Error(err);
    }
}

export function addJob({ queue, stock, period, milliseconds, triggeredBy }) {
  if (milliseconds) {
    return queue.add(
      { stock, period, triggeredBy },
      { delay: milliseconds, jobId: uniqueId }
    );
  } else {
    return queue.add({ stock, period, triggeredBy }, { jobId: uniqueId });
  }
}

ลองนี้สิ! ฉันพยายาม refactor รหัสเล็กน้อยโดยใช้ async รอ


ฉันได้แก้ไขคำถามแล้วคุณช่วยลองดูอีกครั้งได้ไหมโดยเฉพาะส่วน "การแก้ไขล่าช้าที่สำคัญ"? คำตอบของคุณยังคงใช้ในสถานการณ์นี้หรือไม่? ขอบคุณ
salep
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.