@sap/cds
Version:
SAP Cloud Application Programming Model - CDS for Node.js
96 lines (86 loc) • 2.79 kB
JavaScript
const PROCESSING = 'processing'
const LOCKED = 'locked'
const QUEUED = 'queued'
const PLANNED = 'planned'
const CALLBACKS = 'callbacks'
module.exports = class TaskRunner {
constructor() {
this.states = new Map()
}
_setStateProp(prop, state, { name, tenant }) {
const statesSrv = this.states.get(name)
if (!statesSrv) {
const newStatesSrv = new Map()
newStatesSrv.set(tenant, { [prop]: state })
this.states.set(name, newStatesSrv)
return state
}
const obj = statesSrv.get(tenant)
if (!obj) {
statesSrv.set(tenant, { [prop]: state })
return state
}
obj[prop] = state
return state
}
_getStateProp(prop, { name, tenant }) {
const statesSrv = this.states.get(name)
if (!statesSrv) return
const obj = statesSrv.get(tenant)
return obj && obj[prop]
}
run({ name, tenant }, cb) {
const processingState = this._getStateProp(PROCESSING, { name, tenant })
if (processingState === LOCKED) {
this._setStateProp(PROCESSING, QUEUED, { name, tenant })
return
}
if (processingState === QUEUED) return
if (!processingState) this._setStateProp(PROCESSING, LOCKED, { name, tenant })
return cb()
}
// Allows to plan, the shortest time wins
plan({ name, tenant, waitingTime }, cb) {
const newDate = Date.now() + waitingTime
const alreadyPlanned = this._getStateProp(PLANNED, { name, tenant })
if (!alreadyPlanned || alreadyPlanned.date > newDate) {
if (alreadyPlanned) clearInterval(alreadyPlanned.timer)
this._setStateProp(
PLANNED,
{
date: newDate,
timer: setTimeout(() => (this._setStateProp(PLANNED, undefined, { name, tenant }), cb()), waitingTime)
},
{ name, tenant }
)
}
}
end({ name, tenant }, cb) {
const processingState = this._getStateProp(PROCESSING, { name, tenant })
this._setStateProp(PROCESSING, undefined, { name, tenant })
if (processingState === QUEUED) {
cb()
} else {
// Truly done - call all done callbacks
const callbacks = this.clearCallbacks({ name, tenant })
if (callbacks) {
callbacks.forEach(callback => callback())
}
}
}
getCallbacks({ name, tenant }) {
return this._getStateProp(CALLBACKS, { name, tenant })
}
addCallback({ name, tenant }, callback) {
const existing = this._getStateProp(CALLBACKS, { name, tenant }) || []
if (!existing.includes(callback)) {
existing.push(callback)
this._setStateProp(CALLBACKS, existing, { name, tenant })
}
}
clearCallbacks({ name, tenant }) {
const callbacks = this._getStateProp(CALLBACKS, { name, tenant })
this._setStateProp(CALLBACKS, undefined, { name, tenant })
return callbacks
}
}