agendash 1.0.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Dockerfile +3 -2
- package/History.md +80 -58
- package/LICENSE +1 -1
- package/README.md +173 -49
- package/all-jobs.png +0 -0
- package/app.js +12 -7
- package/bin/agendash-standalone-fastify.js +61 -0
- package/bin/agendash-standalone-hapi.js +60 -0
- package/bin/agendash-standalone-koa.js +56 -0
- package/bin/agendash-standalone.js +47 -15
- package/create-job.png +0 -0
- package/entrypoint.sh +1 -1
- package/lib/controllers/agendash.js +340 -0
- package/lib/middlewares/README.md +12 -5
- package/lib/middlewares/express.js +58 -34
- package/lib/middlewares/fastify.js +75 -0
- package/lib/middlewares/hapi.js +65 -88
- package/lib/middlewares/koa.js +71 -0
- package/mobile-ui-sm.png +0 -0
- package/mobile-ui-xs.png +0 -0
- package/package.json +45 -36
- package/public/android-chrome-192x192.png +0 -0
- package/public/android-chrome-512x512.png +0 -0
- package/public/app/assets/ArgensdashV2Logo.svg +18 -0
- package/public/app/css/styles.css +221 -0
- package/public/app/js/confirmDelete.js +40 -0
- package/public/app/js/confirmDeleteMulti.js +45 -0
- package/public/app/js/confirmRequeue.js +40 -0
- package/public/app/js/confirmRequeueMulti.js +45 -0
- package/public/app/js/confirms.js +8 -0
- package/public/app/js/jobdetail.js +48 -0
- package/public/app/js/joblist.js +239 -0
- package/public/app/js/main.js +275 -0
- package/public/app/js/newJob.js +89 -0
- package/public/app/js/sidebar.js +121 -0
- package/public/app/js/topbar.js +95 -0
- package/public/apple-touch-icon.png +0 -0
- package/public/favicon-16x16.png +0 -0
- package/public/favicon-32x32.png +0 -0
- package/public/favicon.ico +0 -0
- package/public/index.html +40 -164
- package/public/site.webmanifest +1 -0
- package/search.png +0 -0
- package/.editorconfig +0 -7
- package/.travis.yml +0 -24
- package/job-details.png +0 -0
- package/lib/agendash.js +0 -295
- package/public/css/bootstrap-theme.css +0 -587
- package/public/css/bootstrap-theme.css.map +0 -1
- package/public/css/bootstrap-theme.min.css +0 -6
- package/public/css/bootstrap-theme.min.css.map +0 -1
- package/public/css/bootstrap.css +0 -6760
- package/public/css/bootstrap.css.map +0 -1
- package/public/css/bootstrap.min.css +0 -6
- package/public/css/bootstrap.min.css.map +0 -1
- package/public/css/dashboard.css +0 -94
- package/public/fonts/glyphicons-halflings-regular.eot +0 -0
- package/public/fonts/glyphicons-halflings-regular.svg +0 -288
- package/public/fonts/glyphicons-halflings-regular.ttf +0 -0
- package/public/fonts/glyphicons-halflings-regular.woff +0 -0
- package/public/fonts/glyphicons-halflings-regular.woff2 +0 -0
- package/public/js/backbone-min.js +0 -2
- package/public/js/backbone-min.map +0 -1
- package/public/js/bootstrap.js +0 -2363
- package/public/js/bootstrap.min.js +0 -7
- package/public/js/jquery-2.2.0.min.js +0 -4
- package/public/js/lodash.min.js +0 -120
- package/public/js/main.js +0 -414
- package/public/js/moment.min.js +0 -7
- package/test/test-express.js +0 -98
- package/test/test-hapi.js +0 -104
- package/yarn.lock +0 -4412
package/public/index.html
CHANGED
|
@@ -7,173 +7,49 @@
|
|
|
7
7
|
|
|
8
8
|
<title>Agendash</title>
|
|
9
9
|
|
|
10
|
-
<link
|
|
11
|
-
<link
|
|
10
|
+
<link rel="apple-touch-icon" sizes="180x180" href="apple-touch-icon.png">
|
|
11
|
+
<link rel="icon" type="image/png" sizes="32x32" href="favicon-32x32.png">
|
|
12
|
+
<link rel="icon" type="image/png" sizes="16x16" href="favicon-16x16.png">
|
|
13
|
+
<link rel="manifest" href="site.webmanifest">
|
|
14
|
+
|
|
15
|
+
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
|
|
16
|
+
integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
|
|
17
|
+
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js"
|
|
18
|
+
integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
|
|
19
|
+
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"
|
|
20
|
+
integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
|
|
21
|
+
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"
|
|
22
|
+
integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
|
|
23
|
+
<link href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;1,300;1,400;1,500;1,900&display=swap" rel="stylesheet">
|
|
24
|
+
<link href="https://fonts.googleapis.com/css2?family=Days+One&display=swap" rel="stylesheet">
|
|
25
|
+
<link href="https://fonts.googleapis.com/icon?family=Material+Icons"
|
|
26
|
+
rel="stylesheet">
|
|
27
|
+
<link href="https://cdn.jsdelivr.net/npm/prismjs@1.20.0/themes/prism.css" rel="stylesheet" />
|
|
28
|
+
<link rel="stylesheet" href="https://unpkg.com/vue-prism-editor@0.6.1/dist/VuePrismEditor.css">
|
|
29
|
+
<link href="app/css/styles.css" rel="stylesheet">
|
|
12
30
|
</head>
|
|
13
|
-
|
|
14
31
|
<body>
|
|
15
|
-
<div id="
|
|
16
|
-
<
|
|
17
|
-
<div class="sidebar-header">
|
|
18
|
-
<h1 class="page-title"></h1>
|
|
19
|
-
<div class="form-group">
|
|
20
|
-
<label for="overviewFilter">Filter by name</label>
|
|
21
|
-
<input type="text" class="overview-filter form-control">
|
|
22
|
-
</div>
|
|
23
|
-
<div class="form-group">
|
|
24
|
-
<label for="overviewFilter">Refresh interval (seconds)</label>
|
|
25
|
-
<input type="number" value="2" class="refresh-interval form-control">
|
|
26
|
-
</div>
|
|
27
|
-
</div>
|
|
28
|
-
<div id="job-overview-list"></div>
|
|
29
|
-
</div>
|
|
30
|
-
<div id="main-pane">
|
|
31
|
-
<div id="list-pane">
|
|
32
|
-
<div class="page-header">
|
|
33
|
-
<h2 id="active-title">
|
|
34
|
-
<span class="active-job"></span>
|
|
35
|
-
<small class="active-state"></small>
|
|
36
|
-
</h2>
|
|
37
|
-
<ul id="select-jobs" class="nav nav-pills">
|
|
38
|
-
<li role="presentation"><a role="button" data-action="schedule-job">Schedule job</a></li>
|
|
39
|
-
<li role="presentation"><a role="button" data-action="select-all">Select all</a></li>
|
|
40
|
-
<li role="presentation"><a role="button" data-action="select-none">Select none</a></li>
|
|
41
|
-
</ul>
|
|
42
|
-
<div class="clearfix"></div>
|
|
43
|
-
</div>
|
|
44
|
-
<div class="table-responsive">
|
|
45
|
-
<table class="table">
|
|
46
|
-
<thead>
|
|
47
|
-
<tr>
|
|
48
|
-
<th>Status</th>
|
|
49
|
-
<th>Name</th>
|
|
50
|
-
<th>Last run started</th>
|
|
51
|
-
<th>Next run starts</th>
|
|
52
|
-
<th>Last finished</th>
|
|
53
|
-
<th>Locked</th>
|
|
54
|
-
</tr>
|
|
55
|
-
</thead>
|
|
56
|
-
<tbody id="job-list"></tbody>
|
|
57
|
-
</table>
|
|
58
|
-
</div>
|
|
59
|
-
</div>
|
|
60
|
-
<div id="details-pane">
|
|
61
|
-
<h2 class="sub-header"><span class="number-selected">0</span> <small>selected</small></h2>
|
|
62
|
-
<button type="button" class="btn btn-danger btn-xs" data-action="requeue-jobs">Requeue selected</button>
|
|
63
|
-
<button type="button" class="btn btn-danger btn-xs pull-right" data-action="delete-jobs">Delete selected</button>
|
|
64
|
-
<hr />
|
|
65
|
-
<div id="details-list"></div>
|
|
66
|
-
</div>
|
|
67
|
-
<div id="create-job-pane">
|
|
68
|
-
<h2 class="sub-header">Create Job</h2>
|
|
69
|
-
<hr />
|
|
70
|
-
<div class="form-group">
|
|
71
|
-
<label>Job name</label>
|
|
72
|
-
<input type="text" class="job-name form-control">
|
|
73
|
-
</div>
|
|
74
|
-
<div class="form-group">
|
|
75
|
-
<label>Schedule</label>
|
|
76
|
-
<input type="text" class="job-schedule form-control">
|
|
77
|
-
</div>
|
|
78
|
-
<div class="form-group">
|
|
79
|
-
<label>Repeat every</label>
|
|
80
|
-
<input type="text" class="job-repeat-every form-control">
|
|
81
|
-
</div>
|
|
82
|
-
<div class="form-group">
|
|
83
|
-
<label>Job data (json)</label>
|
|
84
|
-
<textarea class="job-data form-control">{}</textarea>
|
|
85
|
-
</div>
|
|
86
|
-
<div class="form-group">
|
|
87
|
-
<span class="btn btn-default btn-success" data-action="save">Save</span>
|
|
88
|
-
<span class="btn btn-default btn-warning" data-action="cancel">Cancel</span>
|
|
89
|
-
</div>
|
|
90
|
-
</div>
|
|
91
|
-
</div>
|
|
32
|
+
<div id="agendash-root">
|
|
33
|
+
<app></app>
|
|
92
34
|
</div>
|
|
93
|
-
|
|
94
|
-
<script
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
<li data-state="queued"><a class="text-primary" href="#">Queued<span class="label label-primary pull-right"><%- queued %></span></a></li>
|
|
112
|
-
<li data-state="running"><a class="text-warning" href="#">Running<span class="label label-warning pull-right"><%- running %></span></a></li>
|
|
113
|
-
<li data-state="completed"><a class="text-success" href="#">Completed<span class="label label-success pull-right"><%- completed %></span></a></li>
|
|
114
|
-
<li data-state="failed"><a class="text-danger" href="#">Failed<span class="label label-danger pull-right"><%- failed %></span></a></li>
|
|
115
|
-
<li data-state="repeating"><a class="text-info" href="#">Repeating<span class="label label-info pull-right"><%- repeating %></span></a></li>
|
|
116
|
-
</ul>
|
|
117
|
-
</ul>
|
|
35
|
+
<script src="https://cdn.jsdelivr.net/combine/npm/prismjs@1.20.0,npm/vue-prism-editor@0.6.1,npm/prismjs@1.20.0/plugins/autoloader/prism-autoloader.min.js"></script>
|
|
36
|
+
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
|
|
37
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.21.1/axios.min.js"></script>
|
|
38
|
+
<script src="https://cdn.jsdelivr.net/npm/moment@2.24.0/moment.min.js"></script>
|
|
39
|
+
<script src="app/js/confirms.js"></script>
|
|
40
|
+
<script src="app/js/confirmDelete.js"></script>
|
|
41
|
+
<script src="app/js/confirmDeleteMulti.js"></script>
|
|
42
|
+
<script src="app/js/confirmRequeue.js"></script>
|
|
43
|
+
<script src="app/js/confirmRequeueMulti.js"></script>
|
|
44
|
+
<script src="app/js/newJob.js"></script>
|
|
45
|
+
<script src="app/js/jobdetail.js"></script>
|
|
46
|
+
<script src="app/js/joblist.js"></script>
|
|
47
|
+
<script src="app/js/sidebar.js"></script>
|
|
48
|
+
<script src="app/js/topbar.js"></script>
|
|
49
|
+
<script src="app/js/main.js"></script>
|
|
50
|
+
<script>
|
|
51
|
+
Vue.component('prism-editor', VuePrismEditor)
|
|
52
|
+
new Vue({ el: '#agendash-root' })
|
|
118
53
|
</script>
|
|
119
|
-
|
|
120
|
-
<script type="text/template" id="job-item-template">
|
|
121
|
-
<td>
|
|
122
|
-
<% if (repeating) { %><span class="label label-info"><i class="glyphicon glyphicon-repeat"></i> <%- job.repeatInterval %></span><% } %>
|
|
123
|
-
<% if (scheduled) { %><span class="label label-info">Scheduled</span><% } %>
|
|
124
|
-
<% if (queued) { %><span class="label label-primary">Queued</span><% } %>
|
|
125
|
-
<% if (running) { %><span class="label label-warning">Running</span><% } %>
|
|
126
|
-
<% if (completed) { %><span class="label label-success">Completed</span><% } %>
|
|
127
|
-
<% if (failed) { %><span class="label label-danger">Failed</span><% } %>
|
|
128
|
-
</td>
|
|
129
|
-
<td>
|
|
130
|
-
<%- job.name %>
|
|
131
|
-
</td>
|
|
132
|
-
<td><% if (job.lastRunAt) { %><time datetime="<%- moment(job.lastRunAt).toISOString() %>"><%- moment(job.lastRunAt).fromNow() %></time><% } %></td>
|
|
133
|
-
<td><% if (job.nextRunAt) { %><time datetime="<%- moment(job.nextRunAt).toISOString() %>"><%- moment(job.nextRunAt).fromNow() %></time><% } %></td>
|
|
134
|
-
<td><% if (job.lastFinishedAt) { %><time datetime="<%- moment(job.lastFinishedAt).toISOString() %>"><%- moment(job.lastFinishedAt).fromNow() %></time><% } %></td>
|
|
135
|
-
<td><% if (job.lockedAt) { %><time datetime="<%- moment(job.lockedAt).toISOString() %>"><%- moment(job.lockedAt).fromNow() %></time><% } %></td>
|
|
136
|
-
</script>
|
|
137
|
-
|
|
138
|
-
<script type="text/template" id="job-item-details-template">
|
|
139
|
-
<div class="panel panel-default">
|
|
140
|
-
<div class="panel-heading">
|
|
141
|
-
<button type="button" class="close" aria-label="Close"><span aria-hidden="true">×</span></button>
|
|
142
|
-
<h3 class="panel-title"><%- job.name %></h3>
|
|
143
|
-
<% if (repeating) { %><span class="label label-info"><i class="glyphicon glyphicon-repeat"></i> <%- job.repeatInterval %></span><% } %>
|
|
144
|
-
<% if (scheduled) { %><span class="label label-info">Scheduled</span><% } %>
|
|
145
|
-
<% if (queued) { %><span class="label label-primary">Queued</span><% } %>
|
|
146
|
-
<% if (running) { %><span class="label label-warning">Running</span><% } %>
|
|
147
|
-
<% if (completed) { %><span class="label label-success">Completed</span><% } %>
|
|
148
|
-
<% if (failed) { %><span class="label label-danger">Failed</span><% } %>
|
|
149
|
-
</div>
|
|
150
|
-
<div class="panel-body">
|
|
151
|
-
<% if (job.lastRunAt) { %><p>Last run <time datetime="<%- moment(job.lastRunAt).toISOString() %>"><%- moment(job.lastRunAt).fromNow() %></time></p><% } %>
|
|
152
|
-
<% if (job.nextRunAt) { %><p>Next run <time datetime="<%- moment(job.nextRunAt).toISOString() %>"><%- moment(job.nextRunAt).fromNow() %></time></p><% } %>
|
|
153
|
-
<% if (job.lastFinishedAt) { %><p>Last finished <time datetime="<%- moment(job.lastFinishedAt).toISOString() %>"><%- moment(job.lastFinishedAt).fromNow() %></time></p><% } %>
|
|
154
|
-
<% if (job.lockedAt) { %><p>Locked <time datetime="<%- moment(job.lockedAt).toISOString() %>"><%- moment(job.lockedAt).fromNow() %></time></p><% } %>
|
|
155
|
-
<% if (job.repeatInterval) { %><p>Repeat each <%- job.repeatInterval %></p><% } %>
|
|
156
|
-
|
|
157
|
-
<strong>Job data</strong>
|
|
158
|
-
<pre><%- JSON.stringify(job.data, null, 2) %></pre>
|
|
159
|
-
<% if (failed) { %>
|
|
160
|
-
<strong>Failure reason</strong>
|
|
161
|
-
<pre><%- JSON.stringify(job.failReason || '', null, 2) %></pre>
|
|
162
|
-
<% } %>
|
|
163
|
-
</div>
|
|
164
|
-
<div class="panel-footer clearfix">
|
|
165
|
-
<button type="button" class="btn btn-danger btn-sm" data-action="requeue">Requeue</button>
|
|
166
|
-
<button type="button" class="btn btn-danger btn-sm pull-right" data-action="delete">Delete permanently</button>
|
|
167
|
-
</div>
|
|
168
|
-
</div>
|
|
169
|
-
</script>
|
|
170
|
-
|
|
171
|
-
<script src="js/jquery-2.2.0.min.js"></script>
|
|
172
|
-
<script src="js/lodash.min.js"></script>
|
|
173
|
-
<script src="js/bootstrap.min.js"></script>
|
|
174
|
-
<script src="js/backbone-min.js"></script>
|
|
175
|
-
<script src="js/moment.min.js"></script>
|
|
176
|
-
<script src="js/main.js"></script>
|
|
177
|
-
|
|
178
54
|
</body>
|
|
179
55
|
</html>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"name":"Agendash","short_name":"Agendash","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}
|
package/search.png
ADDED
|
Binary file
|
package/.editorconfig
DELETED
package/.travis.yml
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
language: node_js
|
|
2
|
-
node_js:
|
|
3
|
-
- 8
|
|
4
|
-
- 9
|
|
5
|
-
- 10
|
|
6
|
-
matrix:
|
|
7
|
-
fast_finish: true
|
|
8
|
-
services:
|
|
9
|
-
- mongodb
|
|
10
|
-
sudo: false
|
|
11
|
-
addons:
|
|
12
|
-
apt:
|
|
13
|
-
sources:
|
|
14
|
-
- mongodb-upstart
|
|
15
|
-
packages:
|
|
16
|
-
- mongodb-org-server
|
|
17
|
-
- mongodb-org-shell
|
|
18
|
-
before_script:
|
|
19
|
-
- mongo --version
|
|
20
|
-
- mongod --version
|
|
21
|
-
- 'if [ "$AGENDA_VERSION" ]; then yarn add agenda@$AGENDA_VERSION; fi'
|
|
22
|
-
- 'until nc -z 127.0.0.1 27017 ; do echo Waiting for MongoDB; sleep 1; done'
|
|
23
|
-
env:
|
|
24
|
-
- AGENDA_VERSION=^2.0.0
|
package/job-details.png
DELETED
|
Binary file
|
package/lib/agendash.js
DELETED
|
@@ -1,295 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
const async = require('async');
|
|
3
|
-
const semver = require('semver');
|
|
4
|
-
|
|
5
|
-
module.exports = function(agenda, options) {
|
|
6
|
-
options = options || {};
|
|
7
|
-
|
|
8
|
-
agenda.on('ready', () => {
|
|
9
|
-
const collection = agenda._collection.collection || agenda._collection;
|
|
10
|
-
collection.createIndexes([
|
|
11
|
-
{key: {nextRunAt: -1, lastRunAt: -1, lastFinishedAt: -1}},
|
|
12
|
-
{key: {name: 1, nextRunAt: -1, lastRunAt: -1, lastFinishedAt: -1}}
|
|
13
|
-
], err => {
|
|
14
|
-
if (err) {
|
|
15
|
-
console.warn('Agendash indexes might not exist. Performance may decrease.');
|
|
16
|
-
}
|
|
17
|
-
});
|
|
18
|
-
agenda._mdb.admin().serverInfo((err, serverInfo) => {
|
|
19
|
-
if (err) {
|
|
20
|
-
throw err;
|
|
21
|
-
}
|
|
22
|
-
if (!semver.satisfies(serverInfo.version, '>=2.6.0')) {
|
|
23
|
-
console.warn('Agendash requires mongodb version >=2.6.0.');
|
|
24
|
-
}
|
|
25
|
-
});
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
const getJobs = (job, state, callback) => {
|
|
29
|
-
const preMatch = {};
|
|
30
|
-
if (job) {
|
|
31
|
-
preMatch.name = job;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const postMatch = {};
|
|
35
|
-
if (state) {
|
|
36
|
-
postMatch[state] = true;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const limit = 200; // @TODO: UI param
|
|
40
|
-
const skip = 0; // @TODO: UI param
|
|
41
|
-
|
|
42
|
-
const collection = agenda._collection.collection || agenda._collection;
|
|
43
|
-
collection.aggregate([
|
|
44
|
-
{$match: preMatch},
|
|
45
|
-
{$sort: {
|
|
46
|
-
nextRunAt: -1,
|
|
47
|
-
lastRunAt: -1,
|
|
48
|
-
lastFinishedAt: -1
|
|
49
|
-
}},
|
|
50
|
-
{$project: {
|
|
51
|
-
_id: 0,
|
|
52
|
-
job: '$$ROOT',
|
|
53
|
-
nextRunAt: {$ifNull: ['$nextRunAt', 0]},
|
|
54
|
-
lockedAt: {$ifNull: ['$lockedAt', 0]},
|
|
55
|
-
lastRunAt: {$ifNull: ['$lastRunAt', 0]},
|
|
56
|
-
lastFinishedAt: {$ifNull: ['$lastFinishedAt', 0]},
|
|
57
|
-
failedAt: {$ifNull: ['$failedAt', 0]},
|
|
58
|
-
repeatInterval: {$ifNull: ['$repeatInterval', 0]}
|
|
59
|
-
}},
|
|
60
|
-
{$project: {
|
|
61
|
-
job: '$job',
|
|
62
|
-
_id: '$job._id',
|
|
63
|
-
running: {$and: [
|
|
64
|
-
'$lastRunAt',
|
|
65
|
-
{$gt: ['$lastRunAt', '$lastFinishedAt']}
|
|
66
|
-
]},
|
|
67
|
-
scheduled: {$and: [
|
|
68
|
-
'$nextRunAt',
|
|
69
|
-
{$gte: ['$nextRunAt', new Date()]}
|
|
70
|
-
]},
|
|
71
|
-
queued: {$and: [
|
|
72
|
-
'$nextRunAt',
|
|
73
|
-
{$gte: [new Date(), '$nextRunAt']},
|
|
74
|
-
{$gte: ['$nextRunAt', '$lastFinishedAt']}
|
|
75
|
-
]},
|
|
76
|
-
completed: {$and: [
|
|
77
|
-
'$lastFinishedAt',
|
|
78
|
-
{$gt: ['$lastFinishedAt', '$failedAt']}
|
|
79
|
-
]},
|
|
80
|
-
failed: {$and: [
|
|
81
|
-
'$lastFinishedAt',
|
|
82
|
-
'$failedAt',
|
|
83
|
-
{$eq: ['$lastFinishedAt', '$failedAt']}
|
|
84
|
-
]},
|
|
85
|
-
repeating: {$and: [
|
|
86
|
-
'$repeatInterval',
|
|
87
|
-
{$ne: ['$repeatInterval', null]}
|
|
88
|
-
]}
|
|
89
|
-
}},
|
|
90
|
-
{$match: postMatch},
|
|
91
|
-
{$limit: limit},
|
|
92
|
-
{$skip: skip}
|
|
93
|
-
]).toArray((err, results) => {
|
|
94
|
-
if (err) {
|
|
95
|
-
return callback(err);
|
|
96
|
-
}
|
|
97
|
-
callback(null, results);
|
|
98
|
-
});
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
const getOverview = callback => {
|
|
102
|
-
const collection = agenda._collection.collection || agenda._collection;
|
|
103
|
-
collection.aggregate([
|
|
104
|
-
{$project: {
|
|
105
|
-
_id: 0,
|
|
106
|
-
name: '$name',
|
|
107
|
-
type: '$type',
|
|
108
|
-
priority: '$priority',
|
|
109
|
-
repeatInterval: '$repeatInterval',
|
|
110
|
-
repeatTimezone: '$repeatTimezone',
|
|
111
|
-
nextRunAt: {$ifNull: ['$nextRunAt', 0]},
|
|
112
|
-
lockedAt: {$ifNull: ['$lockedAt', 0]},
|
|
113
|
-
lastRunAt: {$ifNull: ['$lastRunAt', 0]},
|
|
114
|
-
lastFinishedAt: {$ifNull: ['$lastFinishedAt', 0]},
|
|
115
|
-
failedAt: {$ifNull: ['$failedAt', 0]}
|
|
116
|
-
}},
|
|
117
|
-
{$project: {
|
|
118
|
-
name: '$name',
|
|
119
|
-
type: '$type',
|
|
120
|
-
priority: '$priority',
|
|
121
|
-
repeatInterval: '$repeatInterval',
|
|
122
|
-
repeatTimezone: '$repeatTimezone',
|
|
123
|
-
running: {$cond: [{$and: [
|
|
124
|
-
'$lastRunAt',
|
|
125
|
-
{$gt: ['$lastRunAt', '$lastFinishedAt']}
|
|
126
|
-
]}, 1, 0]},
|
|
127
|
-
scheduled: {$cond: [{$and: [
|
|
128
|
-
'$nextRunAt',
|
|
129
|
-
{$gte: ['$nextRunAt', new Date()]}
|
|
130
|
-
]}, 1, 0]},
|
|
131
|
-
queued: {$cond: [{$and: [
|
|
132
|
-
'$nextRunAt',
|
|
133
|
-
{$gte: [new Date(), '$nextRunAt']},
|
|
134
|
-
{$gte: ['$nextRunAt', '$lastFinishedAt']}
|
|
135
|
-
]}, 1, 0]},
|
|
136
|
-
completed: {$cond: [{$and: [
|
|
137
|
-
'$lastFinishedAt',
|
|
138
|
-
{$gt: ['$lastFinishedAt', '$failedAt']}
|
|
139
|
-
]}, 1, 0]},
|
|
140
|
-
failed: {$cond: [{$and: [
|
|
141
|
-
'$lastFinishedAt',
|
|
142
|
-
'$failedAt',
|
|
143
|
-
{$eq: ['$lastFinishedAt', '$failedAt']}
|
|
144
|
-
]}, 1, 0]},
|
|
145
|
-
repeating: {$cond: [{$and: [
|
|
146
|
-
'$repeatInterval',
|
|
147
|
-
{$ne: ['$repeatInterval', null]}
|
|
148
|
-
]}, 1, 0]}
|
|
149
|
-
}},
|
|
150
|
-
{$group: {
|
|
151
|
-
_id: '$name',
|
|
152
|
-
displayName: {$first: '$name'},
|
|
153
|
-
meta: {$addToSet: {
|
|
154
|
-
type: '$type',
|
|
155
|
-
priority: '$priority',
|
|
156
|
-
repeatInterval: '$repeatInterval',
|
|
157
|
-
repeatTimezone: '$repeatTimezone'
|
|
158
|
-
}},
|
|
159
|
-
total: {$sum: 1},
|
|
160
|
-
running: {$sum: '$running'},
|
|
161
|
-
scheduled: {$sum: '$scheduled'},
|
|
162
|
-
queued: {$sum: '$queued'},
|
|
163
|
-
completed: {$sum: '$completed'},
|
|
164
|
-
failed: {$sum: '$failed'},
|
|
165
|
-
repeating: {$sum: '$repeating'}
|
|
166
|
-
}}
|
|
167
|
-
]).toArray((err, results) => {
|
|
168
|
-
if (err) {
|
|
169
|
-
return callback(err);
|
|
170
|
-
}
|
|
171
|
-
const totals = {displayName: 'All Jobs'};
|
|
172
|
-
const states = ['total', 'running', 'scheduled', 'queued', 'completed', 'failed', 'repeating'];
|
|
173
|
-
states.forEach(state => {
|
|
174
|
-
totals[state] = 0;
|
|
175
|
-
});
|
|
176
|
-
results.forEach(job => {
|
|
177
|
-
states.forEach(state => {
|
|
178
|
-
totals[state] += job[state];
|
|
179
|
-
});
|
|
180
|
-
});
|
|
181
|
-
results.unshift(totals);
|
|
182
|
-
callback(null, results);
|
|
183
|
-
});
|
|
184
|
-
};
|
|
185
|
-
|
|
186
|
-
const api = function(job, state, callback) {
|
|
187
|
-
if (!agenda) {
|
|
188
|
-
return callback('Agenda instance is not ready');
|
|
189
|
-
}
|
|
190
|
-
async.parallel({
|
|
191
|
-
overview: getOverview,
|
|
192
|
-
jobs: getJobs.bind(this, job, state)
|
|
193
|
-
},
|
|
194
|
-
(err, apiResponse) => {
|
|
195
|
-
if (err) {
|
|
196
|
-
return callback(err.message);
|
|
197
|
-
}
|
|
198
|
-
apiResponse.title = options.title || 'Agendash';
|
|
199
|
-
apiResponse.currentRequest = {
|
|
200
|
-
title: options.title || 'Agendash',
|
|
201
|
-
job: job || 'All Jobs',
|
|
202
|
-
state
|
|
203
|
-
};
|
|
204
|
-
callback(null, apiResponse);
|
|
205
|
-
});
|
|
206
|
-
};
|
|
207
|
-
|
|
208
|
-
const requeueJobs = (jobIds, callback) => {
|
|
209
|
-
if (!agenda) {
|
|
210
|
-
return callback('Agenda instance is not ready');
|
|
211
|
-
}
|
|
212
|
-
try {
|
|
213
|
-
const collection = agenda._collection.collection || agenda._collection;
|
|
214
|
-
collection
|
|
215
|
-
.find({_id: {$in: jobIds.map(jobId => collection.s.pkFactory(jobId))}})
|
|
216
|
-
.toArray((err, jobs) => {
|
|
217
|
-
if (err || jobs.length === 0) {
|
|
218
|
-
return callback('Jobs not found');
|
|
219
|
-
}
|
|
220
|
-
async.series(jobs.map(job => done => {
|
|
221
|
-
const newJob = agenda.create(job.name, job.data);
|
|
222
|
-
newJob.save()
|
|
223
|
-
.then(() => {
|
|
224
|
-
done(null, newJob);
|
|
225
|
-
})
|
|
226
|
-
.catch(err => {
|
|
227
|
-
done(err);
|
|
228
|
-
});
|
|
229
|
-
}), (err, results) => {
|
|
230
|
-
callback(err, results);
|
|
231
|
-
});
|
|
232
|
-
});
|
|
233
|
-
} catch (err) {
|
|
234
|
-
callback(err.message);
|
|
235
|
-
}
|
|
236
|
-
};
|
|
237
|
-
|
|
238
|
-
const deleteJobs = (jobIds, callback) => {
|
|
239
|
-
if (!agenda) {
|
|
240
|
-
return callback('Agenda instance is not ready');
|
|
241
|
-
}
|
|
242
|
-
try {
|
|
243
|
-
const collection = agenda._collection.collection || agenda._collection;
|
|
244
|
-
agenda.cancel({_id: {$in: jobIds.map(jobId => collection.s.pkFactory(jobId))}})
|
|
245
|
-
.then(deleted => {
|
|
246
|
-
if (deleted) {
|
|
247
|
-
callback();
|
|
248
|
-
} else {
|
|
249
|
-
callback('Jobs not deleted');
|
|
250
|
-
}
|
|
251
|
-
})
|
|
252
|
-
.catch(err => {
|
|
253
|
-
callback(err);
|
|
254
|
-
});
|
|
255
|
-
} catch (err) {
|
|
256
|
-
callback(err.message);
|
|
257
|
-
}
|
|
258
|
-
};
|
|
259
|
-
|
|
260
|
-
const createJob = (jobName, jobSchedule, jobRepeatEvery, jobData, callback) => {
|
|
261
|
-
if (!agenda) {
|
|
262
|
-
return callback('Agenda instance is not ready');
|
|
263
|
-
}
|
|
264
|
-
try {
|
|
265
|
-
// @TODO: Need to validate user input.
|
|
266
|
-
const job = agenda.create(jobName, jobData);
|
|
267
|
-
if (jobSchedule && jobRepeatEvery) {
|
|
268
|
-
job.repeatAt(jobSchedule);
|
|
269
|
-
job.repeatEvery(jobRepeatEvery);
|
|
270
|
-
} else if (jobSchedule) {
|
|
271
|
-
job.schedule(jobSchedule);
|
|
272
|
-
} else if (jobRepeatEvery) {
|
|
273
|
-
job.repeatEvery(jobRepeatEvery);
|
|
274
|
-
} else {
|
|
275
|
-
return callback('Jobs not created');
|
|
276
|
-
}
|
|
277
|
-
job.save()
|
|
278
|
-
.then(() => {
|
|
279
|
-
callback();
|
|
280
|
-
})
|
|
281
|
-
.catch(() => {
|
|
282
|
-
return callback('Jobs not created');
|
|
283
|
-
});
|
|
284
|
-
} catch (err) {
|
|
285
|
-
callback(err.message);
|
|
286
|
-
}
|
|
287
|
-
};
|
|
288
|
-
|
|
289
|
-
return {
|
|
290
|
-
api,
|
|
291
|
-
requeueJobs,
|
|
292
|
-
deleteJobs,
|
|
293
|
-
createJob
|
|
294
|
-
};
|
|
295
|
-
};
|