Bir işin Bull'da iki kez çalışmadığından nasıl emin olabilirim?


11

İki fonksiyonum var scheduleScan()ve scan().

scan()çağrılar scheduleScan() Yeni bir tarama zamanlama dışında yapacak başka bir şey yokken , bu yüzden scheduleScan()bir planlayabilirsiniz scan(). Ama bir sorun var, bazı işler iki kez çalışıyor.

Herhangi bir zamanda yalnızca bir işin işlendiğinden emin olmak istiyorum. Bunu nasıl başarabilirim? Bunun bir ilgisi olduğuna inanıyorum done(), (şimdi tarandı (), kaldırıldı) ama bir çözüm bulamadım.

Boğa sürümü: 3.12.1

Önemli geç düzenleme: scan() başka işlevleri çağırır ve diğer işlevleri çağırabilir veya çağırabilirler, ancak hepsi senkronizasyon işlevleridir, bu nedenle yalnızca kendi işleri tamamlandığında bir işlevi çağırırlar, yalnızca bir yol vardır. "Ağacın" sonunda, ben diyorum, son işlev scheduleScan () çağırır, ama aynı anda çalışan iki iş olamaz. Her iş scan()bu arada başlar ve biter.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İşlev bulamıyorum , yardımcı olabilir misiniz?
Muhammad Zeeshan

@MuhammadZeeshan Ekledim, hatam.
salep

Yanıtlar:


6

Sorun, inanıyorum ki senin scanfonksiyon async. Böylece job.progressfonksiyonunuz çağrılır scanve hemen sonra donesıranın başka bir işi işlemesine izin verir.

Çözüm, donegeri aramayı sizin scanve scheduleScanişlevlerinize bir parametre olarak iletmek ve işinizi tamamladıktan sonra (veya hatayla) çağırmak olabilir.

Başka (daha iyi) çözümü her zaman bir dönüş sağlamak için olabilir Promisegelen scanve scheduleScandaha sonra çözmek ve daha sonra çağırmak için söz beklemektedir done. Bunu yapıyorsanız, tüm vaat getirilerinizi scheduleScanfonksiyonunuza zincirlediğinizden emin olun .

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

}

Sorumu düzenledim, lütfen tekrar kontrol edebilir misiniz, özellikle "Önemli geç düzenleme" bölümü? Cevabınız bu durumda hala geçerli mi? Teşekkürler.
salep

1
Evet, hala geçerli. Düzenlemenizden, scheduledScanher zaman diğer tüm senkronizasyon işlevlerinden sonra çağrıldığını söylüyorsunuz scan. Bu durumda, evet, cevabım hala geçerli. Sadece hep dönen edilecektir sözünü dönmek scheduleScande scanişlev
Jeeves'in

Yine, benim hatam. İlk işlev olan update () taramadadır, ancak update (), finalize () gibi başka bir işlevi çağırabilir ve finalize () scheduleScan () öğesini çağırabilir. Bunların bir sırada gerçekleştiğini lütfen unutmayın, bu nedenle birden fazla çağrı yoktur, bunu modülerimi korumak için yapıyorum. - Teşekkürler
salep

1
Evet, aynı cevap. updateAramalar scheduledScanveya aralarında herhangi bir sayıda işlev varsa . Anahtar nokta, söz zincirini scheduleScantekrar scanişleve geri döndürmeniz gerektiğidir . Yani eğer scançağrılar updatehangi aramalar finalisearamaları ..... scheduleScansöz zincirini tüm işlev çağırmaları yoluyla iade edilmesi gerekir, yani sadece emin bu fonksiyonların her birinden söz dönmek olun.
jeeves

Sadece son yorumumu netleştirmek için. Örneğin, taramanın içinde güncellemeyi çağırırsanız. Güncelleme sonucunu (bir söz) tarama işlevinden döndürmeniz gerekir.
jeeves

4

Tarama işlevi eşzamansız bir işlevdir. Eğer içinde queue.process()işlev tarama işlevini bekliyor ve sonra aramak zorunda done()geri arama.

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

Bunu dene! Async-await kullanarak kodu biraz refactor denedim.


Sorumu düzenledim, lütfen tekrar kontrol edebilir misiniz, özellikle "Önemli geç düzenleme" bölümü? Cevabınız bu durumda hala geçerli mi? Teşekkürler.
salep
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.