2019-05-03 18:43:04 +00:00
|
|
|
'use strict'
|
|
|
|
|
|
|
|
const EventEmitter = require('events').EventEmitter
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Queuing Class for connection queuing
|
|
|
|
*/
|
|
|
|
|
2019-05-27 07:19:53 +00:00
|
|
|
const QueueEvent = {
|
2019-05-20 08:04:35 +00:00
|
|
|
Tick: 'Tick',
|
|
|
|
Push: 'Push',
|
|
|
|
Finish: 'Finish'
|
2019-05-03 18:43:04 +00:00
|
|
|
}
|
|
|
|
|
2019-05-27 07:19:53 +00:00
|
|
|
class ProcessQueue extends EventEmitter {
|
2019-05-20 08:04:35 +00:00
|
|
|
constructor ({
|
|
|
|
maximumLength = 500,
|
|
|
|
triggerTimeInterval = 5000,
|
|
|
|
// execute on push
|
|
|
|
proactiveMode = true,
|
|
|
|
// execute next work on finish
|
|
|
|
continuousMode = true
|
|
|
|
}) {
|
2019-05-03 18:43:04 +00:00
|
|
|
super()
|
|
|
|
this.max = maximumLength
|
|
|
|
this.triggerTime = triggerTimeInterval
|
2019-05-27 07:19:53 +00:00
|
|
|
this.taskMap = new Map()
|
2019-05-03 18:43:04 +00:00
|
|
|
this.queue = []
|
|
|
|
this.lock = false
|
|
|
|
|
2019-05-20 08:04:35 +00:00
|
|
|
this.on(QueueEvent.Tick, this.onEventProcessFunc.bind(this))
|
|
|
|
if (proactiveMode) {
|
|
|
|
this.on(QueueEvent.Push, this.onEventProcessFunc.bind(this))
|
|
|
|
}
|
|
|
|
if (continuousMode) {
|
|
|
|
this.on(QueueEvent.Finish, this.onEventProcessFunc.bind(this))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
onEventProcessFunc () {
|
|
|
|
if (this.lock) return
|
|
|
|
this.lock = true
|
|
|
|
setImmediate(() => {
|
|
|
|
this.process()
|
2019-05-03 18:43:04 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
start () {
|
|
|
|
if (this.eventTrigger) return
|
|
|
|
this.eventTrigger = setInterval(() => {
|
2019-05-27 07:19:53 +00:00
|
|
|
this.emit(QueueEvent.Tick)
|
2019-05-03 18:43:04 +00:00
|
|
|
}, this.triggerTime)
|
|
|
|
}
|
|
|
|
|
|
|
|
stop () {
|
|
|
|
if (this.eventTrigger) {
|
|
|
|
clearInterval(this.eventTrigger)
|
|
|
|
this.eventTrigger = null
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-27 07:19:53 +00:00
|
|
|
checkTaskIsInQueue (id) {
|
|
|
|
return this.taskMap.has(id)
|
|
|
|
}
|
|
|
|
|
2019-05-03 18:43:04 +00:00
|
|
|
/**
|
2019-05-27 07:19:53 +00:00
|
|
|
* pushWithKey a promisify-task to queue
|
|
|
|
* @param id {string}
|
|
|
|
* @param processingFunc {Function<Promise>}
|
|
|
|
* @returns {boolean} if success return true, otherwise false
|
2019-05-03 18:43:04 +00:00
|
|
|
*/
|
2019-05-27 07:19:53 +00:00
|
|
|
push (id, processingFunc) {
|
2019-05-03 18:43:04 +00:00
|
|
|
if (this.queue.length >= this.max) return false
|
2019-05-27 07:19:53 +00:00
|
|
|
if (this.checkTaskIsInQueue(id)) return false
|
|
|
|
const task = {
|
|
|
|
id: id,
|
|
|
|
processingFunc: processingFunc
|
|
|
|
}
|
|
|
|
this.taskMap.set(id, true)
|
2019-05-03 18:43:04 +00:00
|
|
|
this.queue.push(task)
|
|
|
|
this.start()
|
2019-05-20 08:04:35 +00:00
|
|
|
this.emit(QueueEvent.Push)
|
2019-05-03 18:43:04 +00:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
process () {
|
|
|
|
if (this.queue.length <= 0) {
|
|
|
|
this.stop()
|
|
|
|
this.lock = false
|
|
|
|
return
|
|
|
|
}
|
2019-05-27 07:19:53 +00:00
|
|
|
|
2019-05-03 18:43:04 +00:00
|
|
|
const task = this.queue.shift()
|
2019-05-27 07:19:53 +00:00
|
|
|
this.taskMap.delete(task.id)
|
2019-05-03 18:43:04 +00:00
|
|
|
|
|
|
|
const finishTask = () => {
|
|
|
|
this.lock = false
|
|
|
|
setImmediate(() => {
|
2019-05-20 08:04:35 +00:00
|
|
|
this.emit(QueueEvent.Finish)
|
2019-05-03 18:43:04 +00:00
|
|
|
})
|
|
|
|
}
|
2019-05-27 07:19:53 +00:00
|
|
|
task.processingFunc().then(finishTask).catch(finishTask)
|
2019-05-03 18:43:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-27 07:19:53 +00:00
|
|
|
exports.ProcessQueue = ProcessQueue
|