Làm thế nào tôi có thể chắc chắn rằng một công việc không chạy hai lần trong Bull?


11

Tôi có hai chức năng, scheduleScan()scan().

scan()gọi scheduleScan() khi không có gì khác để làm ngoại trừ lên lịch quét mới , vì vậyscheduleScan() có thể lên lịch a scan(). Nhưng có một vấn đề, một số công việc chạy hai lần.

Tôi muốn đảm bảo rằng chỉ có một công việc đang được xử lý tại bất kỳ thời điểm nào. Làm thế nào tôi có thể đạt được điều đó? Tôi tin rằng nó có cái gì đó để làm vớidone() , (nó đã được quét (), loại bỏ ngay bây giờ) nhưng tôi không thể đưa ra giải pháp.

Phiên bản Bull: 3.12.1

Chỉnh sửa muộn quan trọng: scan() gọi các chức năng khác và chúng có thể hoặc không thể gọi các chức năng khác, nhưng chúng đều là các chức năng đồng bộ hóa, vì vậy chúng chỉ gọi một chức năng khi công việc của chúng được hoàn thành, chỉ còn một cách. Ở cuối "cây", tôi gọi nó, hàm cuối cùng gọi calendarScan (), nhưng không thể có hai công việc đồng thời chạy. Nhân tiện, mọi công việc đều bắt đầu scan(), và họ kết thúc bằngscheduleScan(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)
      })
    }
  })
}

Tôi không thể tìm thấy scanchức năng, bạn có thể giúp đỡ?
Muhammad Zeeshan

@MuhammadZeeshan Tôi đã thêm nó, lỗi của tôi.
salep

Câu trả lời:


6

Vấn đề, tôi tin là scanchức năng của bạn là không đồng bộ. Vì vậy, job.progresschức năng của bạn gọiscan và sau đó gọi ngay lập tức donecho phép hàng đợi xử lý một công việc khác.

Một giải pháp có thể là chuyển cuộc donegọi lại dưới dạng tham số cho hàm scanscheduleScanhàm của bạn và gọi nó, sau khi bạn đã hoàn thành công việc của mình (hoặc bị lỗi).

Một giải pháp khác (tốt hơn) có thể là đảm bảo rằng bạn luôn trả lại Promisetừ scanscheduleScansau đó chờ đợi lời hứa để giải quyết và sau đó gọi done. Nếu làm điều này, hãy chắc chắn rằng bạn xâu chuỗi tất cả lời hứa trong scheduleScanhàm của bạn .

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;
             })

}

Tôi đã chỉnh sửa câu hỏi của mình, bạn có thể vui lòng kiểm tra lại không, đặc biệt là phần "Chỉnh sửa trễ quan trọng"? Câu trả lời của bạn vẫn được áp dụng trong tình huống này? Cảm ơn.
salep

1
Vâng, nó vẫn còn hiệu lực. Từ chỉnh sửa của bạn, tôi nghĩ bạn đang nói scheduledScanluôn được gọi sau tất cả các chức năng đồng bộ hóa khác scan. Nếu đây là trường hợp, thì có, câu trả lời của tôi vẫn còn hiệu lực. Chỉ cần luôn luôn trả lại lời hứa sẽ được trả lại scheduleScantrong scanchức năng
jeeves

Một lần nữa, sai lầm của tôi. Hàm đầu tiên, update (), đang quét, nhưng update () có thể gọi một hàm khác như Finalize () và Finalize () có thể gọi calendarScan (). Xin lưu ý rằng những điều này xảy ra theo một thứ tự, vì vậy không có nhiều cuộc gọi, tôi đang làm điều này để giữ cho ứng dụng của mình được mô đun hóa. - Cảm ơn
salep

1
Đúng, cùng một câu trả lời. Nếu updatecuộc gọi scheduledScanhoặc bất kỳ số lượng chức năng giữa chúng. Điểm mấu chốt là bạn cần trả lại chuỗi lời hứa từ scheduleScantất cả các cách trở lại scanchức năng. Vì vậy, nếu scancác cuộc gọi updatenào gọi finalise..... scheduleScanCuộc gọi nào sẽ được trả về chuỗi lời hứa thông qua tất cả các lệnh gọi hàm, tức là chỉ cần đảm bảo bạn trả lại lời hứa từ mỗi hàm này.
Jeeves

Vì vậy, chỉ để làm rõ nhận xét cuối cùng của tôi. Ví dụ, nếu bên trong quét bạn gọi cập nhật. Bạn cần trả về kết quả cập nhật (một lời hứa) từ chức năng quét.
jeeves

4

Chức năng quét là một chức năng không đồng bộ. Trong queue.process()chức năng của bạn, bạn phải chờ chức năng quét và sau đó gọi done()lại.

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 });
  }
}

Thử cái này! Tôi đã cố gắng cấu trúc lại mã một chút bằng cách sử dụng async-await.


Tôi đã chỉnh sửa câu hỏi của mình, bạn có thể vui lòng kiểm tra lại không, đặc biệt là phần "Chỉnh sửa trễ quan trọng"? Câu trả lời của bạn vẫn được áp dụng trong tình huống này? Cảm ơn.
salep
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.