diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..de1b7db6 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,7 @@ +version: '3.2' +services: + redis: + image: redis:6-alpine + container_name: redis-6 + ports: + - 6379:6379 diff --git a/example/bee.js b/example/bee.js index 7f804726..fa62cc6d 100644 --- a/example/bee.js +++ b/example/bee.js @@ -30,7 +30,7 @@ async function main() { .delayUntil(Date.now() + 60 * 1000) .save(); - const job = await queue.createJob({}).save(); + await queue.createJob({}).save(); Arena( { diff --git a/example/bull.js b/example/bull.js index a4146e22..62acf9c2 100644 --- a/example/bull.js +++ b/example/bull.js @@ -39,7 +39,7 @@ async function main() { } }); - await queue.add({}); + await queue.add({data: 'data'}); // adding delayed jobs const delayedJob = await queue.add({}, {delay: 60 * 1000}); diff --git a/package.json b/package.json index 9bc5c382..09972819 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,8 @@ "ci": "npm run lint && if [ -z \"$CI\" ]; then npm run ci:commitlint; fi", "ci:commitlint": "commitlint --from \"origin/${GITHUB_BASE_REF:-master}\"", "cm": "git cz", + "dc:up": "docker-compose -f docker-compose.yml up -d", + "dc:down": "docker-compose -f docker-compose.yml down", "dry:run": "npm publish --dry-run", "lint": "prettier -c .", "lint:staged": "lint-staged", diff --git a/public/dashboard.js b/public/dashboard.js index 6375c9f2..268abb5c 100644 --- a/public/dashboard.js +++ b/public/dashboard.js @@ -314,6 +314,38 @@ $(document).ready(() => { }); }); + $('.js-update-job-data').on('click', function (e) { + e.preventDefault(); + const jobId = $(this).data('job-id'); + const queueName = $(this).data('queue-name'); + const queueHost = $(this).data('queue-host'); + const stringifiedData = JSON.stringify(window.jsonEditor.get()); + const r = window.confirm( + `Update job #${jobId} data in queue "${queueHost}/${queueName}"?` + ); + + if (r) { + $.ajax({ + url: `${basePath}/api/queue/${encodeURIComponent( + queueHost + )}/${encodeURIComponent(queueName)}/job/${encodeURIComponent( + jobId + )}/data`, + type: 'PUT', + data: stringifiedData, + contentType: 'application/json', + }) + .done(() => { + alert('Job data successfully updated!'); + window.location.reload(); + }) + .fail((jqXHR) => { + window.alert('Failed to update job data, check console for error.'); + console.error(jqXHR.responseText); + }); + } + }); + $('.js-add-flow').on('click', function () { const data = window.jsonEditor.get(); const flow = JSON.stringify({data}); diff --git a/src/server/views/api/index.js b/src/server/views/api/index.js index 50523e44..12b53987 100644 --- a/src/server/views/api/index.js +++ b/src/server/views/api/index.js @@ -6,6 +6,7 @@ const jobAdd = require('./jobAdd'); const jobPromote = require('./jobPromote'); const jobRetry = require('./jobRetry'); const jobRemove = require('./jobRemove'); +const jobDataUpdate = require('./jobDataUpdate'); const repeatableJobRemove = require('./repeatableJobRemove'); const bulkJobsPromote = require('./bulkJobsPromote'); const bulkJobsRemove = require('./bulkJobsRemove'); @@ -24,6 +25,7 @@ router.delete( '/queue/:queueHost/:queueName/repeatable/job/:id', repeatableJobRemove ); +router.put('/queue/:queueHost/:queueName/job/:id/data', jobDataUpdate); router.patch('/queue/:queueHost/:queueName/job/:id', jobRetry); router.put('/queue/:queueHost/:queueName/pause', queuePause); router.put('/queue/:queueHost/:queueName/resume', queueResume); diff --git a/src/server/views/api/jobDataUpdate.js b/src/server/views/api/jobDataUpdate.js new file mode 100644 index 00000000..e9cdb5ea --- /dev/null +++ b/src/server/views/api/jobDataUpdate.js @@ -0,0 +1,25 @@ +async function handler(req, res) { + const {queueName, queueHost, id} = req.params; + const data = req.body; + + const {Queues} = req.app.locals; + + const queue = await Queues.get(queueName, queueHost); + if (!queue) return res.status(404).json({error: 'queue not found'}); + + const job = await queue.getJob(id); + if (!job) return res.status(404).send({error: 'job not found'}); + + try { + if (job.updateData) { + await job.updateData(data); + } else { + await job.update(data); + } + } catch (err) { + return res.status(500).json({error: err.message}); + } + return res.sendStatus(200); +} + +module.exports = handler; diff --git a/src/server/views/dashboard/templates/jobDetails.hbs b/src/server/views/dashboard/templates/jobDetails.hbs index 8b06853b..781a51ab 100644 --- a/src/server/views/dashboard/templates/jobDetails.hbs +++ b/src/server/views/dashboard/templates/jobDetails.hbs @@ -1,6 +1,6 @@

Queue {{ queueHost }}/{{ queueName }}

-{{> dashboard/jobDetails job basePath=basePath queueName=queueName queueHost=queueHost jobState=jobState stacktraces=stacktraces}} +{{> dashboard/jobDetails job basePath=basePath queueName=queueName queueHost=queueHost jobState=jobState stacktraces=stacktraces view=true}} {{#contentFor 'sidebar'}}
  • Queues Overview
  • @@ -12,4 +12,11 @@ {{#if hasFlows}}
  • Flows Overview
  • {{/if}} +{{/contentFor}} + +{{#contentFor 'script'}} +if(document.getElementById('jsoneditor')) { + window.jsonEditor = new JSONEditor(document.getElementById('jsoneditor'), { modes: ['code','tree','text'] }); + window.jsonEditor.set({{json job.data true}}) +} {{/contentFor}} \ No newline at end of file diff --git a/src/server/views/partials/dashboard/jobDetails.hbs b/src/server/views/partials/dashboard/jobDetails.hbs index c31f9528..ceffac50 100644 --- a/src/server/views/partials/dashboard/jobDetails.hbs +++ b/src/server/views/partials/dashboard/jobDetails.hbs @@ -75,8 +75,10 @@
    Permalinks
    + {{#unless view}} Job {{ this.id }} + {{/unless}} JSON
    @@ -133,7 +135,36 @@
    Data
    -
    {{json this.data true}}
    + +{{#unless queue.IS_BEE}} +{{#if view }} +
    + +
    +
    +
    +{{/if}} +{{/unless}} +
    {{json this.data true}}
    +{{#unless queue.IS_BEE}} +{{#if view }} +
    +
    +
    +
    +
    +
    Update
    +
    +
    +
    +
    +
    +{{/if}} +{{/unless}} {{#if this.queue.IS_BULLMQ}} {{#if this.parent }}