workmatic 1.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/README.md +508 -0
- package/dashboard/app.js +249 -0
- package/dashboard/index.html +143 -0
- package/dashboard/style.css +464 -0
- package/dist/cli.d.ts +15 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +505 -0
- package/dist/cli.js.map +1 -0
- package/dist/client.d.ts +28 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +99 -0
- package/dist/client.js.map +1 -0
- package/dist/dashboard.d.ts +48 -0
- package/dist/dashboard.d.ts.map +1 -0
- package/dist/dashboard.js +412 -0
- package/dist/dashboard.js.map +1 -0
- package/dist/database.d.ts +29 -0
- package/dist/database.d.ts.map +1 -0
- package/dist/database.js +99 -0
- package/dist/database.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +218 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.d.ts +45 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +64 -0
- package/dist/utils.js.map +1 -0
- package/dist/worker.d.ts +26 -0
- package/dist/worker.d.ts.map +1 -0
- package/dist/worker.js +331 -0
- package/dist/worker.js.map +1 -0
- package/package.json +55 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { DashboardOptions, DashboardMiddlewareOptions, WorkmaticDashboard, DashboardMiddleware } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Create a dashboard HTTP server for monitoring and controlling the job queue
|
|
4
|
+
*
|
|
5
|
+
* @param options - Dashboard options
|
|
6
|
+
* @returns Dashboard instance
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* const dashboard = createDashboard({
|
|
11
|
+
* db,
|
|
12
|
+
* port: 3000,
|
|
13
|
+
* workers: [worker1, worker2]
|
|
14
|
+
* });
|
|
15
|
+
*
|
|
16
|
+
* console.log(`Dashboard running at http://localhost:${dashboard.port}`);
|
|
17
|
+
*
|
|
18
|
+
* // Later, close the server
|
|
19
|
+
* await dashboard.close();
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export declare function createDashboard(options: DashboardOptions): WorkmaticDashboard;
|
|
23
|
+
/**
|
|
24
|
+
* Create an Express-compatible middleware for the dashboard
|
|
25
|
+
*
|
|
26
|
+
* @param options - Middleware options
|
|
27
|
+
* @returns Express middleware function
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```ts
|
|
31
|
+
* import express from 'express';
|
|
32
|
+
* import { createDashboardMiddleware } from 'workmatic';
|
|
33
|
+
*
|
|
34
|
+
* const app = express();
|
|
35
|
+
*
|
|
36
|
+
* // Mount dashboard at /workmatic
|
|
37
|
+
* app.use(createDashboardMiddleware({
|
|
38
|
+
* db,
|
|
39
|
+
* basePath: '/workmatic',
|
|
40
|
+
* workers: [worker]
|
|
41
|
+
* }));
|
|
42
|
+
*
|
|
43
|
+
* app.listen(3000);
|
|
44
|
+
* // Dashboard available at http://localhost:3000/workmatic
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
export declare function createDashboardMiddleware(options: DashboardMiddlewareOptions): DashboardMiddleware;
|
|
48
|
+
//# sourceMappingURL=dashboard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboard.d.ts","sourceRoot":"","sources":["../src/dashboard.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAEV,gBAAgB,EAChB,0BAA0B,EAC1B,kBAAkB,EAElB,mBAAmB,EAGpB,MAAM,YAAY,CAAC;AA+VpB;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,gBAAgB,GAAG,kBAAkB,CA4C7E;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,0BAA0B,GAAG,mBAAmB,CA8BlG"}
|
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
import { createServer } from 'http';
|
|
2
|
+
import { fileURLToPath } from 'url';
|
|
3
|
+
import { dirname, join } from 'path';
|
|
4
|
+
import { readFile } from 'fs/promises';
|
|
5
|
+
import { sql } from 'kysely';
|
|
6
|
+
// Get the directory of this module for static file serving
|
|
7
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
+
const __dirname = dirname(__filename);
|
|
9
|
+
// Content types for static files
|
|
10
|
+
const CONTENT_TYPES = {
|
|
11
|
+
'.html': 'text/html; charset=utf-8',
|
|
12
|
+
'.css': 'text/css; charset=utf-8',
|
|
13
|
+
'.js': 'application/javascript; charset=utf-8',
|
|
14
|
+
'.json': 'application/json; charset=utf-8',
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Create the core request handler (shared between standalone and middleware)
|
|
18
|
+
*/
|
|
19
|
+
function createRequestHandler(db, workerMap, basePath = '') {
|
|
20
|
+
/**
|
|
21
|
+
* Send JSON response
|
|
22
|
+
*/
|
|
23
|
+
function sendJson(res, data, status = 200) {
|
|
24
|
+
res.writeHead(status, { 'Content-Type': 'application/json' });
|
|
25
|
+
res.end(JSON.stringify(data));
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Send error response
|
|
29
|
+
*/
|
|
30
|
+
function sendError(res, message, status = 500) {
|
|
31
|
+
sendJson(res, { error: message }, status);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Parse URL query parameters
|
|
35
|
+
*/
|
|
36
|
+
function parseQuery(url) {
|
|
37
|
+
const queryIndex = url.indexOf('?');
|
|
38
|
+
if (queryIndex === -1)
|
|
39
|
+
return new URLSearchParams();
|
|
40
|
+
return new URLSearchParams(url.slice(queryIndex + 1));
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Get path from URL (removing basePath prefix)
|
|
44
|
+
*/
|
|
45
|
+
function getPath(url) {
|
|
46
|
+
const queryIndex = url.indexOf('?');
|
|
47
|
+
let path = queryIndex === -1 ? url : url.slice(0, queryIndex);
|
|
48
|
+
// Remove basePath prefix if present
|
|
49
|
+
if (basePath && path.startsWith(basePath)) {
|
|
50
|
+
path = path.slice(basePath.length) || '/';
|
|
51
|
+
}
|
|
52
|
+
return path;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* API: Get jobs list
|
|
56
|
+
*/
|
|
57
|
+
async function handleGetJobs(req, res) {
|
|
58
|
+
const query = parseQuery(req.url || '');
|
|
59
|
+
const queueFilter = query.get('queue');
|
|
60
|
+
const statusFilter = query.get('status');
|
|
61
|
+
const limit = Math.min(parseInt(query.get('limit') || '50', 10), 100);
|
|
62
|
+
const offset = parseInt(query.get('offset') || '0', 10);
|
|
63
|
+
let queryBuilder = db
|
|
64
|
+
.selectFrom('workmatic_jobs')
|
|
65
|
+
.select([
|
|
66
|
+
'public_id',
|
|
67
|
+
'queue',
|
|
68
|
+
'payload',
|
|
69
|
+
'status',
|
|
70
|
+
'priority',
|
|
71
|
+
'attempts',
|
|
72
|
+
'max_attempts',
|
|
73
|
+
'run_at',
|
|
74
|
+
'created_at',
|
|
75
|
+
'updated_at',
|
|
76
|
+
'last_error',
|
|
77
|
+
])
|
|
78
|
+
.orderBy('created_at', 'desc')
|
|
79
|
+
.limit(limit)
|
|
80
|
+
.offset(offset);
|
|
81
|
+
if (queueFilter) {
|
|
82
|
+
queryBuilder = queryBuilder.where('queue', '=', queueFilter);
|
|
83
|
+
}
|
|
84
|
+
if (statusFilter) {
|
|
85
|
+
queryBuilder = queryBuilder.where('status', '=', statusFilter);
|
|
86
|
+
}
|
|
87
|
+
const jobs = await queryBuilder.execute();
|
|
88
|
+
// Transform to API format
|
|
89
|
+
const apiJobs = jobs.map(job => ({
|
|
90
|
+
id: job.public_id,
|
|
91
|
+
queue: job.queue,
|
|
92
|
+
payload: JSON.parse(job.payload),
|
|
93
|
+
status: job.status,
|
|
94
|
+
priority: job.priority,
|
|
95
|
+
attempts: job.attempts,
|
|
96
|
+
maxAttempts: job.max_attempts,
|
|
97
|
+
runAt: job.run_at,
|
|
98
|
+
createdAt: job.created_at,
|
|
99
|
+
updatedAt: job.updated_at,
|
|
100
|
+
lastError: job.last_error,
|
|
101
|
+
}));
|
|
102
|
+
sendJson(res, { jobs: apiJobs, limit, offset });
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* API: Get statistics
|
|
106
|
+
*/
|
|
107
|
+
async function handleGetStats(req, res) {
|
|
108
|
+
const query = parseQuery(req.url || '');
|
|
109
|
+
const queueFilter = query.get('queue');
|
|
110
|
+
// Get counts by status
|
|
111
|
+
let statsQuery = db
|
|
112
|
+
.selectFrom('workmatic_jobs')
|
|
113
|
+
.select([
|
|
114
|
+
'status',
|
|
115
|
+
sql `count(*)`.as('count'),
|
|
116
|
+
])
|
|
117
|
+
.groupBy('status');
|
|
118
|
+
if (queueFilter) {
|
|
119
|
+
statsQuery = statsQuery.where('queue', '=', queueFilter);
|
|
120
|
+
}
|
|
121
|
+
const statusCounts = await statsQuery.execute();
|
|
122
|
+
const stats = {
|
|
123
|
+
ready: 0,
|
|
124
|
+
running: 0,
|
|
125
|
+
done: 0,
|
|
126
|
+
failed: 0,
|
|
127
|
+
dead: 0,
|
|
128
|
+
total: 0,
|
|
129
|
+
};
|
|
130
|
+
for (const row of statusCounts) {
|
|
131
|
+
const status = row.status;
|
|
132
|
+
const count = Number(row.count);
|
|
133
|
+
if (status in stats) {
|
|
134
|
+
stats[status] = count;
|
|
135
|
+
}
|
|
136
|
+
stats.total += count;
|
|
137
|
+
}
|
|
138
|
+
// Get queue list
|
|
139
|
+
const queuesResult = await db
|
|
140
|
+
.selectFrom('workmatic_jobs')
|
|
141
|
+
.select('queue')
|
|
142
|
+
.groupBy('queue')
|
|
143
|
+
.execute();
|
|
144
|
+
const queues = queuesResult.map(q => q.queue);
|
|
145
|
+
// Get worker status
|
|
146
|
+
const workersStatus = Array.from(workerMap.entries()).map(([queue, worker]) => ({
|
|
147
|
+
queue,
|
|
148
|
+
running: worker.isRunning,
|
|
149
|
+
paused: worker.isPaused,
|
|
150
|
+
}));
|
|
151
|
+
sendJson(res, { stats, queues, workers: workersStatus });
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* API: Get single job by ID
|
|
155
|
+
*/
|
|
156
|
+
async function handleGetJob(req, res, publicId) {
|
|
157
|
+
const job = await db
|
|
158
|
+
.selectFrom('workmatic_jobs')
|
|
159
|
+
.select([
|
|
160
|
+
'public_id',
|
|
161
|
+
'queue',
|
|
162
|
+
'payload',
|
|
163
|
+
'status',
|
|
164
|
+
'priority',
|
|
165
|
+
'attempts',
|
|
166
|
+
'max_attempts',
|
|
167
|
+
'run_at',
|
|
168
|
+
'lease_until',
|
|
169
|
+
'created_at',
|
|
170
|
+
'updated_at',
|
|
171
|
+
'last_error',
|
|
172
|
+
])
|
|
173
|
+
.where('public_id', '=', publicId)
|
|
174
|
+
.executeTakeFirst();
|
|
175
|
+
if (!job) {
|
|
176
|
+
return sendError(res, 'Job not found', 404);
|
|
177
|
+
}
|
|
178
|
+
sendJson(res, {
|
|
179
|
+
id: job.public_id,
|
|
180
|
+
queue: job.queue,
|
|
181
|
+
payload: JSON.parse(job.payload),
|
|
182
|
+
status: job.status,
|
|
183
|
+
priority: job.priority,
|
|
184
|
+
attempts: job.attempts,
|
|
185
|
+
maxAttempts: job.max_attempts,
|
|
186
|
+
runAt: job.run_at,
|
|
187
|
+
leaseUntil: job.lease_until,
|
|
188
|
+
createdAt: job.created_at,
|
|
189
|
+
updatedAt: job.updated_at,
|
|
190
|
+
lastError: job.last_error,
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* API: Pause worker
|
|
195
|
+
*/
|
|
196
|
+
async function handlePauseWorker(res, queue) {
|
|
197
|
+
const worker = workerMap.get(queue);
|
|
198
|
+
if (!worker) {
|
|
199
|
+
return sendError(res, `Worker for queue '${queue}' not found`, 404);
|
|
200
|
+
}
|
|
201
|
+
worker.pause();
|
|
202
|
+
sendJson(res, { ok: true, queue, paused: true });
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* API: Resume worker
|
|
206
|
+
*/
|
|
207
|
+
async function handleResumeWorker(res, queue) {
|
|
208
|
+
const worker = workerMap.get(queue);
|
|
209
|
+
if (!worker) {
|
|
210
|
+
return sendError(res, `Worker for queue '${queue}' not found`, 404);
|
|
211
|
+
}
|
|
212
|
+
worker.resume();
|
|
213
|
+
sendJson(res, { ok: true, queue, paused: false });
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Serve static files from the dashboard directory
|
|
217
|
+
*/
|
|
218
|
+
async function serveStatic(res, filePath) {
|
|
219
|
+
// Navigate from dist/dashboard.js to dashboard/ directory
|
|
220
|
+
const dashboardDir = join(__dirname, '..', 'dashboard');
|
|
221
|
+
const fullPath = join(dashboardDir, filePath);
|
|
222
|
+
// Determine content type
|
|
223
|
+
const ext = filePath.substring(filePath.lastIndexOf('.')) || '.html';
|
|
224
|
+
const contentType = CONTENT_TYPES[ext] || 'application/octet-stream';
|
|
225
|
+
try {
|
|
226
|
+
const content = await readFile(fullPath, 'utf-8');
|
|
227
|
+
res.writeHead(200, { 'Content-Type': contentType });
|
|
228
|
+
res.end(content);
|
|
229
|
+
}
|
|
230
|
+
catch (error) {
|
|
231
|
+
sendError(res, 'Not found', 404);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Main request handler
|
|
236
|
+
*/
|
|
237
|
+
return async function handleRequest(req, res, next) {
|
|
238
|
+
const path = getPath(req.url || '/');
|
|
239
|
+
// Check if this request is for the dashboard
|
|
240
|
+
const fullUrl = req.url || '/';
|
|
241
|
+
if (basePath && !fullUrl.startsWith(basePath)) {
|
|
242
|
+
// Not our route, call next middleware if available
|
|
243
|
+
if (next)
|
|
244
|
+
next();
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
// CORS headers
|
|
248
|
+
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
249
|
+
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
|
250
|
+
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
|
|
251
|
+
if (req.method === 'OPTIONS') {
|
|
252
|
+
res.writeHead(204);
|
|
253
|
+
res.end();
|
|
254
|
+
return true;
|
|
255
|
+
}
|
|
256
|
+
try {
|
|
257
|
+
// API routes
|
|
258
|
+
if (path === '/api/jobs' && req.method === 'GET') {
|
|
259
|
+
await handleGetJobs(req, res);
|
|
260
|
+
return true;
|
|
261
|
+
}
|
|
262
|
+
if (path === '/api/stats' && req.method === 'GET') {
|
|
263
|
+
await handleGetStats(req, res);
|
|
264
|
+
return true;
|
|
265
|
+
}
|
|
266
|
+
// Single job: /api/jobs/:id
|
|
267
|
+
const jobMatch = path.match(/^\/api\/jobs\/([^/]+)$/);
|
|
268
|
+
if (jobMatch && req.method === 'GET') {
|
|
269
|
+
await handleGetJob(req, res, jobMatch[1]);
|
|
270
|
+
return true;
|
|
271
|
+
}
|
|
272
|
+
// Pause worker: /api/workers/:queue/pause
|
|
273
|
+
const pauseMatch = path.match(/^\/api\/workers\/([^/]+)\/pause$/);
|
|
274
|
+
if (pauseMatch && req.method === 'POST') {
|
|
275
|
+
await handlePauseWorker(res, pauseMatch[1]);
|
|
276
|
+
return true;
|
|
277
|
+
}
|
|
278
|
+
// Resume worker: /api/workers/:queue/resume
|
|
279
|
+
const resumeMatch = path.match(/^\/api\/workers\/([^/]+)\/resume$/);
|
|
280
|
+
if (resumeMatch && req.method === 'POST') {
|
|
281
|
+
await handleResumeWorker(res, resumeMatch[1]);
|
|
282
|
+
return true;
|
|
283
|
+
}
|
|
284
|
+
// Static files
|
|
285
|
+
if (path === '/' || path === '/index.html') {
|
|
286
|
+
await serveStatic(res, 'index.html');
|
|
287
|
+
return true;
|
|
288
|
+
}
|
|
289
|
+
if (path === '/style.css') {
|
|
290
|
+
await serveStatic(res, 'style.css');
|
|
291
|
+
return true;
|
|
292
|
+
}
|
|
293
|
+
if (path === '/app.js') {
|
|
294
|
+
await serveStatic(res, 'app.js');
|
|
295
|
+
return true;
|
|
296
|
+
}
|
|
297
|
+
// 404 for unknown routes under our basePath
|
|
298
|
+
sendError(res, 'Not found', 404);
|
|
299
|
+
return true;
|
|
300
|
+
}
|
|
301
|
+
catch (error) {
|
|
302
|
+
console.error('[workmatic] Dashboard error:', error);
|
|
303
|
+
sendError(res, 'Internal server error', 500);
|
|
304
|
+
return true;
|
|
305
|
+
}
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Create a dashboard HTTP server for monitoring and controlling the job queue
|
|
310
|
+
*
|
|
311
|
+
* @param options - Dashboard options
|
|
312
|
+
* @returns Dashboard instance
|
|
313
|
+
*
|
|
314
|
+
* @example
|
|
315
|
+
* ```ts
|
|
316
|
+
* const dashboard = createDashboard({
|
|
317
|
+
* db,
|
|
318
|
+
* port: 3000,
|
|
319
|
+
* workers: [worker1, worker2]
|
|
320
|
+
* });
|
|
321
|
+
*
|
|
322
|
+
* console.log(`Dashboard running at http://localhost:${dashboard.port}`);
|
|
323
|
+
*
|
|
324
|
+
* // Later, close the server
|
|
325
|
+
* await dashboard.close();
|
|
326
|
+
* ```
|
|
327
|
+
*/
|
|
328
|
+
export function createDashboard(options) {
|
|
329
|
+
const { db, port = 3000, workers = [], } = options;
|
|
330
|
+
if (!db) {
|
|
331
|
+
throw new Error('Database instance is required');
|
|
332
|
+
}
|
|
333
|
+
// Worker registry by queue name
|
|
334
|
+
const workerMap = new Map();
|
|
335
|
+
for (const worker of workers) {
|
|
336
|
+
workerMap.set(worker.queue, worker);
|
|
337
|
+
}
|
|
338
|
+
const handleRequest = createRequestHandler(db, workerMap);
|
|
339
|
+
// Create and start HTTP server
|
|
340
|
+
const server = createServer((req, res) => {
|
|
341
|
+
handleRequest(req, res).catch(error => {
|
|
342
|
+
console.error('[workmatic] Unhandled error:', error);
|
|
343
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
344
|
+
res.end(JSON.stringify({ error: 'Internal server error' }));
|
|
345
|
+
});
|
|
346
|
+
});
|
|
347
|
+
server.listen(port);
|
|
348
|
+
return {
|
|
349
|
+
async close() {
|
|
350
|
+
return new Promise((resolve, reject) => {
|
|
351
|
+
server.close((err) => {
|
|
352
|
+
if (err)
|
|
353
|
+
reject(err);
|
|
354
|
+
else
|
|
355
|
+
resolve();
|
|
356
|
+
});
|
|
357
|
+
});
|
|
358
|
+
},
|
|
359
|
+
get port() {
|
|
360
|
+
return port;
|
|
361
|
+
},
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* Create an Express-compatible middleware for the dashboard
|
|
366
|
+
*
|
|
367
|
+
* @param options - Middleware options
|
|
368
|
+
* @returns Express middleware function
|
|
369
|
+
*
|
|
370
|
+
* @example
|
|
371
|
+
* ```ts
|
|
372
|
+
* import express from 'express';
|
|
373
|
+
* import { createDashboardMiddleware } from 'workmatic';
|
|
374
|
+
*
|
|
375
|
+
* const app = express();
|
|
376
|
+
*
|
|
377
|
+
* // Mount dashboard at /workmatic
|
|
378
|
+
* app.use(createDashboardMiddleware({
|
|
379
|
+
* db,
|
|
380
|
+
* basePath: '/workmatic',
|
|
381
|
+
* workers: [worker]
|
|
382
|
+
* }));
|
|
383
|
+
*
|
|
384
|
+
* app.listen(3000);
|
|
385
|
+
* // Dashboard available at http://localhost:3000/workmatic
|
|
386
|
+
* ```
|
|
387
|
+
*/
|
|
388
|
+
export function createDashboardMiddleware(options) {
|
|
389
|
+
const { db, workers = [], basePath = '', } = options;
|
|
390
|
+
if (!db) {
|
|
391
|
+
throw new Error('Database instance is required');
|
|
392
|
+
}
|
|
393
|
+
// Worker registry by queue name
|
|
394
|
+
const workerMap = new Map();
|
|
395
|
+
for (const worker of workers) {
|
|
396
|
+
workerMap.set(worker.queue, worker);
|
|
397
|
+
}
|
|
398
|
+
const handleRequest = createRequestHandler(db, workerMap, basePath);
|
|
399
|
+
return (req, res, next) => {
|
|
400
|
+
handleRequest(req, res, next).catch(error => {
|
|
401
|
+
console.error('[workmatic] Unhandled error:', error);
|
|
402
|
+
if (next) {
|
|
403
|
+
next();
|
|
404
|
+
}
|
|
405
|
+
else {
|
|
406
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
407
|
+
res.end(JSON.stringify({ error: 'Internal server error' }));
|
|
408
|
+
}
|
|
409
|
+
});
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
//# sourceMappingURL=dashboard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboard.js","sourceRoot":"","sources":["../src/dashboard.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import Database from 'better-sqlite3';
|
|
2
|
+
import type { WorkmaticDb, DatabaseOptions } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Create and initialize the workmatic database
|
|
5
|
+
*
|
|
6
|
+
* @param options - Database options
|
|
7
|
+
* @returns Kysely database instance
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* // Using a file path
|
|
12
|
+
* const db = createDatabase({ filename: './jobs.db' });
|
|
13
|
+
*
|
|
14
|
+
* // Using an existing better-sqlite3 instance
|
|
15
|
+
* import Database from 'better-sqlite3';
|
|
16
|
+
* const sqlite = new Database('./jobs.db');
|
|
17
|
+
* const db = createDatabase({ db: sqlite });
|
|
18
|
+
*
|
|
19
|
+
* // In-memory database (for testing)
|
|
20
|
+
* const db = createDatabase({ filename: ':memory:' });
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export declare function createDatabase(options?: DatabaseOptions): WorkmaticDb;
|
|
24
|
+
/**
|
|
25
|
+
* Get the underlying better-sqlite3 database instance from a Kysely instance
|
|
26
|
+
* This is useful for advanced operations or testing
|
|
27
|
+
*/
|
|
28
|
+
export declare function getUnderlyingDb(db: WorkmaticDb): Database.Database;
|
|
29
|
+
//# sourceMappingURL=database.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../src/database.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAEtC,OAAO,KAAK,EAAqB,WAAW,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,cAAc,CAAC,OAAO,GAAE,eAAoB,GAAG,WAAW,CA0BzE;AAiDD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,WAAW,GAAG,QAAQ,CAAC,QAAQ,CAKlE"}
|
package/dist/database.js
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import Database from 'better-sqlite3';
|
|
2
|
+
import { Kysely, SqliteDialect } from 'kysely';
|
|
3
|
+
/**
|
|
4
|
+
* Create and initialize the workmatic database
|
|
5
|
+
*
|
|
6
|
+
* @param options - Database options
|
|
7
|
+
* @returns Kysely database instance
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* // Using a file path
|
|
12
|
+
* const db = createDatabase({ filename: './jobs.db' });
|
|
13
|
+
*
|
|
14
|
+
* // Using an existing better-sqlite3 instance
|
|
15
|
+
* import Database from 'better-sqlite3';
|
|
16
|
+
* const sqlite = new Database('./jobs.db');
|
|
17
|
+
* const db = createDatabase({ db: sqlite });
|
|
18
|
+
*
|
|
19
|
+
* // In-memory database (for testing)
|
|
20
|
+
* const db = createDatabase({ filename: ':memory:' });
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export function createDatabase(options = {}) {
|
|
24
|
+
let sqliteDb;
|
|
25
|
+
if (options.db) {
|
|
26
|
+
sqliteDb = options.db;
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
const filename = options.filename ?? ':memory:';
|
|
30
|
+
sqliteDb = new Database(filename);
|
|
31
|
+
}
|
|
32
|
+
// Set pragmas for performance and safety
|
|
33
|
+
sqliteDb.pragma('journal_mode = WAL');
|
|
34
|
+
sqliteDb.pragma('synchronous = NORMAL');
|
|
35
|
+
sqliteDb.pragma('busy_timeout = 5000');
|
|
36
|
+
// Create Kysely instance
|
|
37
|
+
const db = new Kysely({
|
|
38
|
+
dialect: new SqliteDialect({
|
|
39
|
+
database: sqliteDb,
|
|
40
|
+
}),
|
|
41
|
+
});
|
|
42
|
+
// Create schema synchronously using better-sqlite3 directly
|
|
43
|
+
createSchema(sqliteDb);
|
|
44
|
+
return db;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Create the database schema if it doesn't exist
|
|
48
|
+
*/
|
|
49
|
+
function createSchema(db) {
|
|
50
|
+
// Create the jobs table
|
|
51
|
+
db.exec(`
|
|
52
|
+
CREATE TABLE IF NOT EXISTS workmatic_jobs (
|
|
53
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
54
|
+
public_id TEXT UNIQUE NOT NULL,
|
|
55
|
+
queue TEXT NOT NULL,
|
|
56
|
+
payload TEXT NOT NULL,
|
|
57
|
+
status TEXT NOT NULL DEFAULT 'ready',
|
|
58
|
+
priority INTEGER NOT NULL DEFAULT 0,
|
|
59
|
+
run_at INTEGER NOT NULL,
|
|
60
|
+
attempts INTEGER NOT NULL DEFAULT 0,
|
|
61
|
+
max_attempts INTEGER NOT NULL DEFAULT 3,
|
|
62
|
+
lease_until INTEGER NOT NULL DEFAULT 0,
|
|
63
|
+
created_at INTEGER NOT NULL,
|
|
64
|
+
updated_at INTEGER NOT NULL,
|
|
65
|
+
last_error TEXT
|
|
66
|
+
)
|
|
67
|
+
`);
|
|
68
|
+
// Create composite index for efficient job claiming
|
|
69
|
+
// (queue, status, run_at, priority, id)
|
|
70
|
+
db.exec(`
|
|
71
|
+
CREATE INDEX IF NOT EXISTS idx_workmatic_jobs_claim
|
|
72
|
+
ON workmatic_jobs (queue, status, run_at, priority, id)
|
|
73
|
+
`);
|
|
74
|
+
// Create index for lease expiration checking
|
|
75
|
+
// (status, lease_until)
|
|
76
|
+
db.exec(`
|
|
77
|
+
CREATE INDEX IF NOT EXISTS idx_workmatic_jobs_lease
|
|
78
|
+
ON workmatic_jobs (status, lease_until)
|
|
79
|
+
`);
|
|
80
|
+
// Create settings table for queue-level settings (pause state, etc.)
|
|
81
|
+
db.exec(`
|
|
82
|
+
CREATE TABLE IF NOT EXISTS workmatic_settings (
|
|
83
|
+
queue TEXT PRIMARY KEY,
|
|
84
|
+
paused INTEGER NOT NULL DEFAULT 0,
|
|
85
|
+
updated_at INTEGER NOT NULL
|
|
86
|
+
)
|
|
87
|
+
`);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Get the underlying better-sqlite3 database instance from a Kysely instance
|
|
91
|
+
* This is useful for advanced operations or testing
|
|
92
|
+
*/
|
|
93
|
+
export function getUnderlyingDb(db) {
|
|
94
|
+
// Access the internal database through the dialect
|
|
95
|
+
// This is a bit hacky but necessary for some operations
|
|
96
|
+
const dialect = db.getExecutor().adapter.db;
|
|
97
|
+
return dialect;
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=database.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"database.js","sourceRoot":"","sources":["../src/database.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AACtC,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AAG/C;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,cAAc,CAAC,UAA2B,EAAE;IAC1D,IAAI,QAA2B,CAAC;IAEhC,IAAI,OAAO,CAAC,EAAE,EAAE,CAAC;QACf,QAAQ,GAAG,OAAO,CAAC,EAAE,CAAC;IACxB,CAAC;SAAM,CAAC;QACN,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,UAAU,CAAC;QAChD,QAAQ,GAAG,IAAI,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACpC,CAAC;IAED,yCAAyC;IACzC,QAAQ,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;IACtC,QAAQ,CAAC,MAAM,CAAC,sBAAsB,CAAC,CAAC;IACxC,QAAQ,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC;IAEvC,yBAAyB;IACzB,MAAM,EAAE,GAAG,IAAI,MAAM,CAAoB;QACvC,OAAO,EAAE,IAAI,aAAa,CAAC;YACzB,QAAQ,EAAE,QAAQ;SACnB,CAAC;KACH,CAAC,CAAC;IAEH,4DAA4D;IAC5D,YAAY,CAAC,QAAQ,CAAC,CAAC;IAEvB,OAAO,EAAE,CAAC;AACZ,CAAC;AAED;;GAEG;AACH,SAAS,YAAY,CAAC,EAAqB;IACzC,wBAAwB;IACxB,EAAE,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;GAgBP,CAAC,CAAC;IAEH,oDAAoD;IACpD,wCAAwC;IACxC,EAAE,CAAC,IAAI,CAAC;;;GAGP,CAAC,CAAC;IAEH,6CAA6C;IAC7C,wBAAwB;IACxB,EAAE,CAAC,IAAI,CAAC;;;GAGP,CAAC,CAAC;IAEH,qEAAqE;IACrE,EAAE,CAAC,IAAI,CAAC;;;;;;GAMP,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,EAAe;IAC7C,mDAAmD;IACnD,wDAAwD;IACxD,MAAM,OAAO,GAAI,EAAU,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;IACrD,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workmatic - A persistent job queue for Node.js
|
|
3
|
+
*
|
|
4
|
+
* @packageDocumentation
|
|
5
|
+
*/
|
|
6
|
+
export { createDatabase } from './database.js';
|
|
7
|
+
export { createClient } from './client.js';
|
|
8
|
+
export { createWorker } from './worker.js';
|
|
9
|
+
export { createDashboard, createDashboardMiddleware } from './dashboard.js';
|
|
10
|
+
export { defaultBackoff, validatePayload } from './utils.js';
|
|
11
|
+
export type { Job, JobStatus, JobStats, ClaimedJob, AddJobOptions, AddJobResult, DatabaseOptions, ClientOptions, WorkerOptions, DashboardOptions, DashboardMiddlewareOptions, BackoffFunction, JobProcessor, WorkmaticClient, WorkmaticWorker, WorkmaticDashboard, DashboardMiddleware, WorkmaticDb, WorkmaticDatabase, WorkmaticJobsTable, } from './types.js';
|
|
12
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAC;AAG5E,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAG7D,YAAY,EAEV,GAAG,EACH,SAAS,EACT,QAAQ,EACR,UAAU,EAGV,aAAa,EACb,YAAY,EACZ,eAAe,EACf,aAAa,EACb,aAAa,EACb,gBAAgB,EAChB,0BAA0B,EAC1B,eAAe,EACf,YAAY,EAGZ,eAAe,EACf,eAAe,EACf,kBAAkB,EAClB,mBAAmB,EACnB,WAAW,EACX,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workmatic - A persistent job queue for Node.js
|
|
3
|
+
*
|
|
4
|
+
* @packageDocumentation
|
|
5
|
+
*/
|
|
6
|
+
// Main exports
|
|
7
|
+
export { createDatabase } from './database.js';
|
|
8
|
+
export { createClient } from './client.js';
|
|
9
|
+
export { createWorker } from './worker.js';
|
|
10
|
+
export { createDashboard, createDashboardMiddleware } from './dashboard.js';
|
|
11
|
+
// Utility exports
|
|
12
|
+
export { defaultBackoff, validatePayload } from './utils.js';
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,eAAe;AACf,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAC;AAE5E,kBAAkB;AAClB,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC"}
|