// admin/job-queue.js // Copyright (C) 2022 DTP Technologies, LLC // All Rights Reserved 'use strict'; const DTP_COMPONENT_NAME = 'admin:job-queue'; const express = require('express'); const { SiteController, SiteError } = require('../../../lib/site-lib'); class JobQueueController extends SiteController { constructor (dtp) { super(dtp, DTP_COMPONENT_NAME); } async start ( ) { const router = express.Router(); router.use(async (req, res, next) => { res.locals.currentView = 'admin'; res.locals.adminView = 'job-queue'; return next(); }); router.param('jobQueueName', this.populateJobQueueName.bind(this)); router.param('jobId', this.populateJob.bind(this)); router.post('/:jobQueueName/:jobId/action', this.postJobAction.bind(this)); router.get('/:jobQueueName/:jobId', this.getJobView.bind(this)); router.get('/:jobQueueName', this.getJobQueueView.bind(this)); router.get('/', this.getHomeView.bind(this)); return router; } async populateJobQueueName (req, res, next, jobQueueName) { const { jobQueue: jobQueueService } = this.dtp.services; try { res.locals.queueName = jobQueueName; res.locals.queue = await jobQueueService.getJobQueue(jobQueueName); if (!res.locals.queue) { throw new SiteError(404, 'Job queue not found'); } return next(); } catch (error) { this.log.error('failed to populate job queue', { jobQueueName, error }); return next(error); } } async populateJob (req, res, next, jobId) { try { res.locals.job = await res.locals.queue.getJob(jobId); if (!res.locals.job) { throw new SiteError(404, 'Job not found'); } return next(); } catch (error) { this.log.error('failed to populate job', { jobId, error }); return next(error); } } async postJobAction (req, res) { try { await res.locals.job[req.body.action](); res.status(200).json({ success: true }); } catch (error) { this.log.error('failed to execute job action', { jobId: res.locals.job.id, action: req.body.action, error, }); res.status(error.statusCode || 500).json({ success: false, message: error.message, }); } } async getJobView (req, res, next) { try { res.locals.jobLogs = await res.locals.queue.getJobLogs(res.locals.job.id); res.render('admin/job-queue/job-view'); } catch (error) { this.log.error('failed to render job view', { error }); return next(error); } } async getJobQueueView (req, res, next) { try { res.locals.jobCounts = await res.locals.queue.getJobCounts(); res.locals.jobs = { waiting: await res.locals.queue.getWaiting(0, 5), active: await res.locals.queue.getActive(0, 5), delayed: await res.locals.queue.getDelayed(0, 5), failed: await res.locals.queue.getFailed(0, 5), }; res.render('admin/job-queue/queue-view'); } catch (error) { this.log.error('failed to populate job queue view', { error }); return next(error); } } async getHomeView (req, res, next) { const { jobQueue: jobQueueService } = this.dtp.services; try { const prefix = process.env.REDIS_KEY_PREFIX || 'dtp'; res.locals.queues = await jobQueueService.discoverJobQueues(`${prefix}:*:id`); res.render('admin/job-queue/index'); } catch (error) { this.log.error('failed to populate job queues view', { error }); return next(error); } } } module.exports = async (dtp) => { let controller = new JobQueueController(dtp); return controller; };