Core synchronous queue with an example worker

This commit is contained in:
2020-11-02 10:51:08 +00:00
parent d6b5b033f2
commit 0a30f2d466
16 changed files with 1103 additions and 1 deletions

89
routes/calc-queue.js Normal file
View File

@@ -0,0 +1,89 @@
const express = require('express')
const statusCodes = require('http-status-codes').StatusCodes
const calcQueueSvc = require('../src/services/calc-queue')
const CalcQueueExceptions = require('../src/services/calc-queue/exceptions.js')
const router = express.Router()
// Return busy/not busy flag
router.get('/busy', function(req, res) {
res.send({ busy: calcQueueSvc.isBusy() })
})
// Get the current queue of tasks
router.get('/queue', function(req, res) {
res.send({ 'queue': calcQueueSvc.getQueue() })
})
// Add a calc task to the queue
router.put('/queue/:id/:calcFn', function(req, res) {
try {
calcQueueSvc.enqueue(req.params.id, req.params.calcFn)
res.send({ success: true })
} catch(ex) {
if (ex instanceof CalcQueueExceptions.AlreadyQueued
|| ex instanceof CalcQueueExceptions.AlreadyInProgress
|| ex instanceof CalcQueueExceptions.CalculationUnknown) {
res.status(
statusCodes.BAD_REQUEST
).send(
{ success: false, error: ex.message }
)
} else {
throw ex
}
}
})
// Remove a task or collection of tasks from the queue
router.delete('/queue/:id', function(req, res) {
calcQueueSvc.dequeue(req.params.id, null)
res.send({ success: true })
})
// Remove a task from the queue
router.delete('/queue/:id/:calcFn', function(req, res) {
calcQueueSvc.dequeue(req.params.id, req.params.calcFn)
res.send({ success: true })
})
// Get the status of a task as a text string
const processStatus = function(id, calcFn) {
if (calcQueueSvc.isInProgress(id, calcFn)) {
return 'in_progress'
} else if (calcQueueSvc.isQueued(id, calcFn)) {
return 'queued'
} else if (calcQueueSvc.isFinished(id, calcFn)) {
return 'finished'
} else {
return 'not_queued'
}
}
// Get the status of the queue and all tasks
router.get('/status', function(req, res) {
res.status(statusCodes.OK).send({
'queued': calcQueueSvc.getQueue(),
'in_progress': calcQueueSvc.getInProgress(),
'finished': calcQueueSvc.getFinished()
})
})
// Get the status of all tasks with by id
router.get('/status/:id', function(req, res) {
res.status(statusCodes.OK).send({
'id': req.params.id,
'status': processStatus(req.params.id, null)
})
})
// Get the status of an individual task
router.get('/status/:id/:calcFn', function(req, res) {
res.status(statusCodes.OK).send({
'id': req.params.id,
'calcFn': req.params.calcFn,
'status': processStatus(req.params.id, req.params.calcFn)
})
})
module.exports = router

37
routes/index.js Normal file
View File

@@ -0,0 +1,37 @@
const dotenv = require('dotenv')
const express = require('express')
const statusCodes = require('http-status-codes').StatusCodes
const createError = require('http-errors')
dotenv.config()
const router = express.Router()
// TODO: Add a mechanism for multiple clients/API keys
const apiKeys = [
process.env.API_KEY
]
// Middleware to verify API access is granted
router.use('/', function(req, res, next){
var key = req.query['api_key'];
// key isn't present
if (!key) {
return next(createError(statusCodes.BAD_REQUEST, 'api key required'))
}
// key is invalid
if (!~apiKeys.indexOf(key)) {
return next(createError(statusCodes.UNAUTHORIZED, 'invalid api key'))
}
// all good, store req.key for route access
req.key = key
next()
})
// Add API routes to default router
router.use('/', require('./calc-queue.js'))
module.exports = router