UNPKG

@xtcry/bull-arena

Version:

An interactive UI dashboard for Bee/Bull Queue

151 lines (150 loc) 5.47 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const _ = require("lodash"); const queueHelpers_1 = require("../../helpers/queueHelpers"); const JobHelpers = require("../../helpers/jobHelpers"); function getStates(queue) { if (queue.IS_BEE) { return queueHelpers_1.BEE_STATES; } if (queue.IS_BULLMQ) { return queueHelpers_1.BULLMQ_STATES; } return queueHelpers_1.BULL_STATES; } /** * Determines if the requested job state lookup is valid. * * @param {String} state * @param {Object} queue Queue that contains which queue package is used (bee, bull or bullmq) * * @return {Boolean} */ function isValidState(state, queue) { const validStates = getStates(queue); return _.includes(validStates, state); } async function handler(req, res) { if (req.params.ext === 'json') return _json(req, res); return _html(req, res); } exports.default = handler; /** * Returns the queue jobs in the requested state as a json document. * * @prop {Object} req express request object * @prop {Object} res express response object */ async function _json(req, res) { const { queueName, queueHost, state } = req.params; const { Queues } = req.app.locals; const queue = await Queues.get(queueName, queueHost); if (!queue) return res.status(404).json({ message: 'Queue not found' }); if (!isValidState(state, queue)) return res .status(400) .json({ message: `Invalid state requested: ${state}` }); let jobs; if (queue.IS_BEE) { jobs = await queue.getJobs(state, { size: 1000 }); jobs = jobs.map((j) => _.pick(j, 'id', 'progress', 'data', 'options', 'status')); } else { const words = state.split('-'); const finalStateName = words.map((word) => _.capitalize(word)).join(''); jobs = await queue[`get${finalStateName}`](0, 1000); jobs = jobs.map((j) => j.toJSON()); } const filename = `${queueName}-${state}-dump.json`; res.setHeader('Content-disposition', `attachment; filename=${filename}`); res.setHeader('Content-type', 'application/json'); res.write(JSON.stringify(jobs, null, 2), () => res.end()); } /** * Renders an html view of the queue jobs in the requested state. * * @prop {Object} req express request object * @prop {Object} res express response object */ async function _html(req, res) { const { queueName, queueHost, state } = req.params; const { Queues, Flows } = req.app.locals; const queue = await Queues.get(queueName, queueHost); const basePath = req.baseUrl; if (!queue) return res.status(404).render('dashboard/queueNotFound', { basePath, queueName, queueHost, }); if (!isValidState(state, queue)) return res .status(400) .json({ message: `Invalid state requested: ${state}` }); let jobCounts; if (queue.IS_BEE) { jobCounts = await queue.checkHealth(); delete jobCounts.newestJob; } else { jobCounts = await queue.getJobCounts(); } const page = parseInt(req.query.page, 10) || 1; const pageSize = parseInt(req.query.pageSize, 10) || 100; const order = req.query.order || 'desc'; const startId = (page - 1) * pageSize; const endId = startId + pageSize - 1; let jobs; if (queue.IS_BEE) { const pageOptions = {}; if (['failed', 'succeeded'].includes(state)) { pageOptions.size = pageSize; } else { pageOptions.start = startId; pageOptions.end = endId; } jobs = await queue.getJobs(state, pageOptions); // Filter out Bee jobs that have already been removed by the time the promise resolves jobs = jobs.filter(Boolean); } else { const stateTypes = state === 'waiting' ? ['wait', 'paused'] : state; jobs = await queue.getJobs(stateTypes, startId, endId, order === 'asc'); } for (const job of jobs) { const jobState = queue.IS_BEE ? job.status : await job.getState(); job.showRetryButton = !queue.IS_BEE || jobState === 'failed'; job.retryButtonText = jobState === 'failed' ? 'Retry' : 'Trigger'; job.showPromoteButton = !queue.IS_BEE && jobState === 'delayed'; job.parent = JobHelpers.getKeyProperties(job.parentKey); } let pages = _.range(page - 6, page + 7).filter((page) => page >= 1); while (pages.length < 12) { pages.push(_.last(pages) + 1); } pages = pages.filter((page) => page <= _.ceil(jobCounts[state] / pageSize)); const disablePromote = !(state === 'delayed' && !queue.IS_BEE); const disableRetry = !(state === 'failed' || (state === 'delayed' && !queue.IS_BEE)); return res.render('dashboard/queueJobsByState', { basePath, queueName, queueHost, state, jobs, jobsInStateCount: jobCounts[state], disablePagination: queue.IS_BEE && (state === 'succeeded' || state === 'failed'), disableOrdering: queue.IS_BEE, disablePromote, disableRetry, currentPage: page, hasFlows: Flows.hasFlows(), pages, pageSize, lastPage: _.last(pages), order, }); }