Bullでジョブが2回実行されないようにするにはどうすればよいですか?


11

私には2つの機能がscheduleScan()ありscan()ます。

scan()scheduleScan() 新しいスキャンをスケジュールする以外に何もすることがないときにを呼び出すので、scheduleScan()をスケジュールできscan()ます。しかし、問題があります。一部のジョブは2回実行されます。

常に1つのジョブのみが処理されていることを確認したいと思います。どうすればそれを達成できますか?私はそれがdone()(scan()に含まれていたが、現在は削除されている)と関係があると思いますが、解決策を見つけることができませんでした。

Bullバージョン:3.12.1

重要な後半の編集: scan()別の関数を呼び出すと、他の関数を呼び出す場合と呼び出さない場合がありますが、それらはすべて同期関数であるため、独自のジョブが完了したときにのみ関数を呼び出します。「ツリー」の最後でそれを呼び出します。最後の関数はscheduleScan()を呼び出しますが、2つのジョブを同時に実行することはできません。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機能が見つかりません、お手伝いできますか?
ムハンマドジーシャン

@MuhammadZeeshan間違いです。
salep

回答:


6

問題は、私はあなたのscan機能が非同期であると信じています。したがって、job.progress関数を呼び出しscanてすぐに呼び出しdone、キューが別のジョブを処理できるようにします。

解決策doneとしては、コールバックをパラメータとしてscanscheduleScan関数に渡し、ジョブが完了したら(またはエラーが発生した場合)コールバックを呼び出すことが考えられます。

別の(より良い)解決策は、必ずPromisefrom scanとを返し、scheduleScan解決の約束を待ってを呼び出すことdoneです。これを行う場合は、scheduleScan関数内のすべてのpromiseリターンをチェーンしてください。

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。これが事実である場合、はい、私の答えはまだ有効です。ただ、常にから返される約束返すscheduleScanscan機能
Jeevesの

もう一度、私の間違い。最初の関数update()はスキャン中ですが、update()はfinalize()のような別の関数を呼び出し、finalize()はscheduleScan()を呼び出します。これらは順番に行われるため、複数の呼び出しはないことに注意してください。これは、アプリをモジュール式に保つために行います。-ありがとう
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 });
  }
}

これを試して!私はasync-awaitを使用してコードを少しリファクタリングしようとしました。


質問を編集しました。特に「重要な遅延編集」の部分をもう一度確認してください。あなたの答えはこの状況でも当てはまりますか?ありがとう。
salep
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.