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
package/dist/cli.js
ADDED
|
@@ -0,0 +1,505 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Workmatic CLI
|
|
4
|
+
*
|
|
5
|
+
* Commands:
|
|
6
|
+
* stats <db> Show job statistics
|
|
7
|
+
* export <db> [output] Export jobs to CSV
|
|
8
|
+
* import <db> <input> Import jobs from CSV
|
|
9
|
+
* purge <db> [--status=done] Delete jobs by status
|
|
10
|
+
* retry <db> [--status=dead] Retry failed/dead jobs
|
|
11
|
+
* pause <db> <queue> Pause a queue (workers stop claiming)
|
|
12
|
+
* resume <db> <queue> Resume a paused queue
|
|
13
|
+
*/
|
|
14
|
+
import Database from 'better-sqlite3';
|
|
15
|
+
import { createReadStream, createWriteStream } from 'fs';
|
|
16
|
+
import { createInterface } from 'readline';
|
|
17
|
+
// Parse command line arguments
|
|
18
|
+
const args = process.argv.slice(2);
|
|
19
|
+
const command = args[0];
|
|
20
|
+
function printUsage() {
|
|
21
|
+
console.log(`
|
|
22
|
+
Workmatic CLI - Job Queue Management
|
|
23
|
+
|
|
24
|
+
Usage:
|
|
25
|
+
workmatic <command> [options]
|
|
26
|
+
|
|
27
|
+
Commands:
|
|
28
|
+
stats <db> Show job statistics
|
|
29
|
+
queues <db> List all queues with status
|
|
30
|
+
list <db> [--status=<status>] List jobs (optionally filter by status)
|
|
31
|
+
export <db> [output.csv] Export jobs to CSV (default: stdout)
|
|
32
|
+
import <db> <input.csv> Import jobs from CSV
|
|
33
|
+
purge <db> --status=<status> Delete jobs by status
|
|
34
|
+
retry <db> [--status=dead] Retry dead/failed jobs (reset to ready)
|
|
35
|
+
pause <db> <queue> Pause a queue (running workers stop claiming)
|
|
36
|
+
resume <db> <queue> Resume a paused queue
|
|
37
|
+
|
|
38
|
+
Options:
|
|
39
|
+
--status=<status> Filter by status (ready|running|done|failed|dead)
|
|
40
|
+
--queue=<queue> Filter by queue name
|
|
41
|
+
--limit=<n> Limit number of results (default: 100)
|
|
42
|
+
|
|
43
|
+
Examples:
|
|
44
|
+
workmatic stats ./jobs.db
|
|
45
|
+
workmatic list ./jobs.db --status=dead --limit=10
|
|
46
|
+
workmatic export ./jobs.db backup.csv
|
|
47
|
+
workmatic export ./jobs.db --status=failed > failed-jobs.csv
|
|
48
|
+
workmatic import ./jobs.db backup.csv
|
|
49
|
+
workmatic purge ./jobs.db --status=done
|
|
50
|
+
workmatic retry ./jobs.db --status=dead
|
|
51
|
+
workmatic pause ./jobs.db emails
|
|
52
|
+
workmatic resume ./jobs.db emails
|
|
53
|
+
`);
|
|
54
|
+
}
|
|
55
|
+
function parseOptions(args) {
|
|
56
|
+
const options = {};
|
|
57
|
+
for (const arg of args) {
|
|
58
|
+
if (arg.startsWith('--')) {
|
|
59
|
+
const [key, value] = arg.slice(2).split('=');
|
|
60
|
+
options[key] = value ?? 'true';
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return options;
|
|
64
|
+
}
|
|
65
|
+
function getPositionalArgs(args) {
|
|
66
|
+
return args.filter(arg => !arg.startsWith('--'));
|
|
67
|
+
}
|
|
68
|
+
// CSV helpers
|
|
69
|
+
function escapeCSV(value) {
|
|
70
|
+
if (value === null)
|
|
71
|
+
return '';
|
|
72
|
+
const str = String(value);
|
|
73
|
+
if (str.includes(',') || str.includes('"') || str.includes('\n')) {
|
|
74
|
+
return `"${str.replace(/"/g, '""')}"`;
|
|
75
|
+
}
|
|
76
|
+
return str;
|
|
77
|
+
}
|
|
78
|
+
function parseCSVLine(line) {
|
|
79
|
+
const result = [];
|
|
80
|
+
let current = '';
|
|
81
|
+
let inQuotes = false;
|
|
82
|
+
for (let i = 0; i < line.length; i++) {
|
|
83
|
+
const char = line[i];
|
|
84
|
+
if (inQuotes) {
|
|
85
|
+
if (char === '"') {
|
|
86
|
+
if (line[i + 1] === '"') {
|
|
87
|
+
current += '"';
|
|
88
|
+
i++;
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
inQuotes = false;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
current += char;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
if (char === '"') {
|
|
100
|
+
inQuotes = true;
|
|
101
|
+
}
|
|
102
|
+
else if (char === ',') {
|
|
103
|
+
result.push(current);
|
|
104
|
+
current = '';
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
current += char;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
result.push(current);
|
|
112
|
+
return result;
|
|
113
|
+
}
|
|
114
|
+
// Commands
|
|
115
|
+
async function cmdStats(dbPath) {
|
|
116
|
+
const db = new Database(dbPath, { readonly: true });
|
|
117
|
+
try {
|
|
118
|
+
const stats = db.prepare(`
|
|
119
|
+
SELECT status, COUNT(*) as count
|
|
120
|
+
FROM workmatic_jobs
|
|
121
|
+
GROUP BY status
|
|
122
|
+
`).all();
|
|
123
|
+
const queues = db.prepare(`
|
|
124
|
+
SELECT queue, COUNT(*) as count
|
|
125
|
+
FROM workmatic_jobs
|
|
126
|
+
GROUP BY queue
|
|
127
|
+
`).all();
|
|
128
|
+
const total = stats.reduce((sum, s) => sum + s.count, 0);
|
|
129
|
+
console.log('\n📊 Job Statistics\n');
|
|
130
|
+
console.log('By Status:');
|
|
131
|
+
console.log('─'.repeat(30));
|
|
132
|
+
const statusOrder = ['ready', 'running', 'done', 'failed', 'dead'];
|
|
133
|
+
const statusEmoji = {
|
|
134
|
+
ready: '⏳',
|
|
135
|
+
running: '▶️ ',
|
|
136
|
+
done: '✅',
|
|
137
|
+
failed: '⚠️ ',
|
|
138
|
+
dead: '💀',
|
|
139
|
+
};
|
|
140
|
+
for (const status of statusOrder) {
|
|
141
|
+
const stat = stats.find(s => s.status === status);
|
|
142
|
+
const count = stat?.count ?? 0;
|
|
143
|
+
const emoji = statusEmoji[status] || ' ';
|
|
144
|
+
console.log(` ${emoji} ${status.padEnd(10)} ${count.toLocaleString().padStart(8)}`);
|
|
145
|
+
}
|
|
146
|
+
console.log('─'.repeat(30));
|
|
147
|
+
console.log(` Total: ${total.toLocaleString().padStart(8)}`);
|
|
148
|
+
if (queues.length > 0) {
|
|
149
|
+
console.log('\nBy Queue:');
|
|
150
|
+
console.log('─'.repeat(30));
|
|
151
|
+
for (const q of queues) {
|
|
152
|
+
console.log(` ${q.queue.padEnd(15)} ${q.count.toLocaleString().padStart(8)}`);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
console.log();
|
|
156
|
+
}
|
|
157
|
+
finally {
|
|
158
|
+
db.close();
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
async function cmdList(dbPath, options) {
|
|
162
|
+
const db = new Database(dbPath, { readonly: true });
|
|
163
|
+
try {
|
|
164
|
+
let query = 'SELECT public_id, queue, status, priority, attempts, max_attempts, created_at, last_error FROM workmatic_jobs WHERE 1=1';
|
|
165
|
+
const params = [];
|
|
166
|
+
if (options.status) {
|
|
167
|
+
query += ' AND status = ?';
|
|
168
|
+
params.push(options.status);
|
|
169
|
+
}
|
|
170
|
+
if (options.queue) {
|
|
171
|
+
query += ' AND queue = ?';
|
|
172
|
+
params.push(options.queue);
|
|
173
|
+
}
|
|
174
|
+
query += ' ORDER BY created_at DESC LIMIT ?';
|
|
175
|
+
params.push(parseInt(options.limit || '100', 10));
|
|
176
|
+
const jobs = db.prepare(query).all(...params);
|
|
177
|
+
if (jobs.length === 0) {
|
|
178
|
+
console.log('No jobs found.');
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
console.log('\nID Queue Status Pri Attempts Created');
|
|
182
|
+
console.log('─'.repeat(85));
|
|
183
|
+
for (const job of jobs) {
|
|
184
|
+
const id = job.public_id.slice(0, 21);
|
|
185
|
+
const queue = job.queue.slice(0, 15).padEnd(15);
|
|
186
|
+
const status = job.status.padEnd(9);
|
|
187
|
+
const pri = String(job.priority).padStart(3);
|
|
188
|
+
const attempts = `${job.attempts}/${job.max_attempts}`.padStart(8);
|
|
189
|
+
const created = new Date(job.created_at).toISOString().slice(0, 19);
|
|
190
|
+
console.log(`${id} ${queue} ${status} ${pri} ${attempts} ${created}`);
|
|
191
|
+
}
|
|
192
|
+
console.log(`\nShowing ${jobs.length} jobs\n`);
|
|
193
|
+
}
|
|
194
|
+
finally {
|
|
195
|
+
db.close();
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
async function cmdExport(dbPath, outputPath, options) {
|
|
199
|
+
const db = new Database(dbPath, { readonly: true });
|
|
200
|
+
try {
|
|
201
|
+
let query = 'SELECT * FROM workmatic_jobs WHERE 1=1';
|
|
202
|
+
const params = [];
|
|
203
|
+
if (options.status) {
|
|
204
|
+
query += ' AND status = ?';
|
|
205
|
+
params.push(options.status);
|
|
206
|
+
}
|
|
207
|
+
if (options.queue) {
|
|
208
|
+
query += ' AND queue = ?';
|
|
209
|
+
params.push(options.queue);
|
|
210
|
+
}
|
|
211
|
+
query += ' ORDER BY id';
|
|
212
|
+
const jobs = db.prepare(query).all(...params);
|
|
213
|
+
const output = outputPath ? createWriteStream(outputPath) : process.stdout;
|
|
214
|
+
// Header
|
|
215
|
+
const columns = [
|
|
216
|
+
'public_id', 'queue', 'payload', 'status', 'priority',
|
|
217
|
+
'run_at', 'attempts', 'max_attempts', 'lease_until',
|
|
218
|
+
'created_at', 'updated_at', 'last_error'
|
|
219
|
+
];
|
|
220
|
+
if (outputPath) {
|
|
221
|
+
output.write(columns.join(',') + '\n');
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
console.log(columns.join(','));
|
|
225
|
+
}
|
|
226
|
+
// Rows
|
|
227
|
+
for (const job of jobs) {
|
|
228
|
+
const row = columns.map(col => escapeCSV(job[col]));
|
|
229
|
+
if (outputPath) {
|
|
230
|
+
output.write(row.join(',') + '\n');
|
|
231
|
+
}
|
|
232
|
+
else {
|
|
233
|
+
console.log(row.join(','));
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
if (outputPath) {
|
|
237
|
+
output.end();
|
|
238
|
+
console.error(`✅ Exported ${jobs.length} jobs to ${outputPath}`);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
finally {
|
|
242
|
+
db.close();
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
async function cmdImport(dbPath, inputPath) {
|
|
246
|
+
const db = new Database(dbPath);
|
|
247
|
+
// Ensure schema exists
|
|
248
|
+
db.exec(`
|
|
249
|
+
CREATE TABLE IF NOT EXISTS workmatic_jobs (
|
|
250
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
251
|
+
public_id TEXT UNIQUE NOT NULL,
|
|
252
|
+
queue TEXT NOT NULL,
|
|
253
|
+
payload TEXT NOT NULL,
|
|
254
|
+
status TEXT NOT NULL DEFAULT 'ready',
|
|
255
|
+
priority INTEGER NOT NULL DEFAULT 0,
|
|
256
|
+
run_at INTEGER NOT NULL,
|
|
257
|
+
attempts INTEGER NOT NULL DEFAULT 0,
|
|
258
|
+
max_attempts INTEGER NOT NULL DEFAULT 3,
|
|
259
|
+
lease_until INTEGER NOT NULL DEFAULT 0,
|
|
260
|
+
created_at INTEGER NOT NULL,
|
|
261
|
+
updated_at INTEGER NOT NULL,
|
|
262
|
+
last_error TEXT
|
|
263
|
+
)
|
|
264
|
+
`);
|
|
265
|
+
const insert = db.prepare(`
|
|
266
|
+
INSERT OR REPLACE INTO workmatic_jobs
|
|
267
|
+
(public_id, queue, payload, status, priority, run_at, attempts, max_attempts, lease_until, created_at, updated_at, last_error)
|
|
268
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
269
|
+
`);
|
|
270
|
+
const rl = createInterface({
|
|
271
|
+
input: createReadStream(inputPath),
|
|
272
|
+
crlfDelay: Infinity,
|
|
273
|
+
});
|
|
274
|
+
let lineNum = 0;
|
|
275
|
+
let imported = 0;
|
|
276
|
+
let columns = [];
|
|
277
|
+
try {
|
|
278
|
+
const insertMany = db.transaction((rows) => {
|
|
279
|
+
for (const row of rows) {
|
|
280
|
+
insert.run(row.public_id, row.queue, row.payload, row.status, parseInt(row.priority, 10) || 0, parseInt(row.run_at, 10) || Date.now(), parseInt(row.attempts, 10) || 0, parseInt(row.max_attempts, 10) || 3, parseInt(row.lease_until, 10) || 0, parseInt(row.created_at, 10) || Date.now(), parseInt(row.updated_at, 10) || Date.now(), row.last_error || null);
|
|
281
|
+
imported++;
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
const batch = [];
|
|
285
|
+
for await (const line of rl) {
|
|
286
|
+
lineNum++;
|
|
287
|
+
if (lineNum === 1) {
|
|
288
|
+
// Header row
|
|
289
|
+
columns = parseCSVLine(line);
|
|
290
|
+
continue;
|
|
291
|
+
}
|
|
292
|
+
if (!line.trim())
|
|
293
|
+
continue;
|
|
294
|
+
const values = parseCSVLine(line);
|
|
295
|
+
const row = {};
|
|
296
|
+
for (let i = 0; i < columns.length; i++) {
|
|
297
|
+
row[columns[i]] = values[i] ?? '';
|
|
298
|
+
}
|
|
299
|
+
batch.push(row);
|
|
300
|
+
// Batch insert every 1000 rows
|
|
301
|
+
if (batch.length >= 1000) {
|
|
302
|
+
insertMany(batch);
|
|
303
|
+
batch.length = 0;
|
|
304
|
+
process.stderr.write(`\rImported ${imported} jobs...`);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
// Insert remaining
|
|
308
|
+
if (batch.length > 0) {
|
|
309
|
+
insertMany(batch);
|
|
310
|
+
}
|
|
311
|
+
console.log(`\n✅ Imported ${imported} jobs from ${inputPath}`);
|
|
312
|
+
}
|
|
313
|
+
finally {
|
|
314
|
+
db.close();
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
async function cmdPurge(dbPath, options) {
|
|
318
|
+
if (!options.status) {
|
|
319
|
+
console.error('Error: --status is required for purge command');
|
|
320
|
+
console.error('Example: workmatic purge ./jobs.db --status=done');
|
|
321
|
+
process.exit(1);
|
|
322
|
+
}
|
|
323
|
+
const db = new Database(dbPath);
|
|
324
|
+
try {
|
|
325
|
+
const result = db.prepare('DELETE FROM workmatic_jobs WHERE status = ?').run(options.status);
|
|
326
|
+
console.log(`🗑️ Deleted ${result.changes} jobs with status '${options.status}'`);
|
|
327
|
+
}
|
|
328
|
+
finally {
|
|
329
|
+
db.close();
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
async function cmdRetry(dbPath, options) {
|
|
333
|
+
const status = options.status || 'dead';
|
|
334
|
+
const db = new Database(dbPath);
|
|
335
|
+
try {
|
|
336
|
+
const now = Date.now();
|
|
337
|
+
const result = db.prepare(`
|
|
338
|
+
UPDATE workmatic_jobs
|
|
339
|
+
SET status = 'ready',
|
|
340
|
+
attempts = 0,
|
|
341
|
+
run_at = ?,
|
|
342
|
+
lease_until = 0,
|
|
343
|
+
updated_at = ?
|
|
344
|
+
WHERE status = ?
|
|
345
|
+
`).run(now, now, status);
|
|
346
|
+
console.log(`🔄 Reset ${result.changes} jobs from '${status}' to 'ready'`);
|
|
347
|
+
}
|
|
348
|
+
finally {
|
|
349
|
+
db.close();
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
async function cmdPause(dbPath, queueName) {
|
|
353
|
+
const db = new Database(dbPath);
|
|
354
|
+
try {
|
|
355
|
+
// Ensure settings table exists
|
|
356
|
+
db.exec(`
|
|
357
|
+
CREATE TABLE IF NOT EXISTS workmatic_settings (
|
|
358
|
+
queue TEXT PRIMARY KEY,
|
|
359
|
+
paused INTEGER NOT NULL DEFAULT 0,
|
|
360
|
+
updated_at INTEGER NOT NULL
|
|
361
|
+
)
|
|
362
|
+
`);
|
|
363
|
+
const now = Date.now();
|
|
364
|
+
db.prepare(`
|
|
365
|
+
INSERT INTO workmatic_settings (queue, paused, updated_at)
|
|
366
|
+
VALUES (?, 1, ?)
|
|
367
|
+
ON CONFLICT(queue) DO UPDATE SET paused = 1, updated_at = ?
|
|
368
|
+
`).run(queueName, now, now);
|
|
369
|
+
console.log(`⏸️ Paused queue '${queueName}'`);
|
|
370
|
+
console.log(` Running workers will stop claiming new jobs.`);
|
|
371
|
+
}
|
|
372
|
+
finally {
|
|
373
|
+
db.close();
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
async function cmdResume(dbPath, queueName) {
|
|
377
|
+
const db = new Database(dbPath);
|
|
378
|
+
try {
|
|
379
|
+
// Ensure settings table exists
|
|
380
|
+
db.exec(`
|
|
381
|
+
CREATE TABLE IF NOT EXISTS workmatic_settings (
|
|
382
|
+
queue TEXT PRIMARY KEY,
|
|
383
|
+
paused INTEGER NOT NULL DEFAULT 0,
|
|
384
|
+
updated_at INTEGER NOT NULL
|
|
385
|
+
)
|
|
386
|
+
`);
|
|
387
|
+
const now = Date.now();
|
|
388
|
+
db.prepare(`
|
|
389
|
+
INSERT INTO workmatic_settings (queue, paused, updated_at)
|
|
390
|
+
VALUES (?, 0, ?)
|
|
391
|
+
ON CONFLICT(queue) DO UPDATE SET paused = 0, updated_at = ?
|
|
392
|
+
`).run(queueName, now, now);
|
|
393
|
+
console.log(`▶️ Resumed queue '${queueName}'`);
|
|
394
|
+
console.log(` Workers will start claiming jobs again.`);
|
|
395
|
+
}
|
|
396
|
+
finally {
|
|
397
|
+
db.close();
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
async function cmdQueues(dbPath) {
|
|
401
|
+
const db = new Database(dbPath, { readonly: true });
|
|
402
|
+
try {
|
|
403
|
+
// Get all queues with their job counts and pause state
|
|
404
|
+
const queues = db.prepare(`
|
|
405
|
+
SELECT
|
|
406
|
+
j.queue,
|
|
407
|
+
COUNT(*) as total,
|
|
408
|
+
SUM(CASE WHEN j.status = 'ready' THEN 1 ELSE 0 END) as ready,
|
|
409
|
+
SUM(CASE WHEN j.status = 'running' THEN 1 ELSE 0 END) as running,
|
|
410
|
+
COALESCE(s.paused, 0) as paused
|
|
411
|
+
FROM workmatic_jobs j
|
|
412
|
+
LEFT JOIN workmatic_settings s ON j.queue = s.queue
|
|
413
|
+
GROUP BY j.queue
|
|
414
|
+
`).all();
|
|
415
|
+
if (queues.length === 0) {
|
|
416
|
+
console.log('No queues found.');
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
console.log('\n📋 Queues\n');
|
|
420
|
+
console.log('Queue Status Ready Running Total');
|
|
421
|
+
console.log('─'.repeat(55));
|
|
422
|
+
for (const q of queues) {
|
|
423
|
+
const name = q.queue.padEnd(16);
|
|
424
|
+
const status = q.paused ? '⏸️ PAUSED' : '▶️ ACTIVE';
|
|
425
|
+
const ready = String(q.ready).padStart(5);
|
|
426
|
+
const running = String(q.running).padStart(8);
|
|
427
|
+
const total = String(q.total).padStart(6);
|
|
428
|
+
console.log(`${name} ${status} ${ready} ${running} ${total}`);
|
|
429
|
+
}
|
|
430
|
+
console.log();
|
|
431
|
+
}
|
|
432
|
+
finally {
|
|
433
|
+
db.close();
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
// Main
|
|
437
|
+
async function main() {
|
|
438
|
+
if (!command || command === '--help' || command === '-h') {
|
|
439
|
+
printUsage();
|
|
440
|
+
process.exit(0);
|
|
441
|
+
}
|
|
442
|
+
const positionalArgs = getPositionalArgs(args.slice(1));
|
|
443
|
+
const options = parseOptions(args);
|
|
444
|
+
const dbPath = positionalArgs[0];
|
|
445
|
+
if (!dbPath) {
|
|
446
|
+
console.error('Error: Database path is required');
|
|
447
|
+
printUsage();
|
|
448
|
+
process.exit(1);
|
|
449
|
+
}
|
|
450
|
+
try {
|
|
451
|
+
switch (command) {
|
|
452
|
+
case 'stats':
|
|
453
|
+
await cmdStats(dbPath);
|
|
454
|
+
break;
|
|
455
|
+
case 'list':
|
|
456
|
+
await cmdList(dbPath, options);
|
|
457
|
+
break;
|
|
458
|
+
case 'export':
|
|
459
|
+
await cmdExport(dbPath, positionalArgs[1], options);
|
|
460
|
+
break;
|
|
461
|
+
case 'import':
|
|
462
|
+
if (!positionalArgs[1]) {
|
|
463
|
+
console.error('Error: Input CSV file is required');
|
|
464
|
+
process.exit(1);
|
|
465
|
+
}
|
|
466
|
+
await cmdImport(dbPath, positionalArgs[1]);
|
|
467
|
+
break;
|
|
468
|
+
case 'purge':
|
|
469
|
+
await cmdPurge(dbPath, options);
|
|
470
|
+
break;
|
|
471
|
+
case 'retry':
|
|
472
|
+
await cmdRetry(dbPath, options);
|
|
473
|
+
break;
|
|
474
|
+
case 'pause':
|
|
475
|
+
if (!positionalArgs[1]) {
|
|
476
|
+
console.error('Error: Queue name is required');
|
|
477
|
+
console.error('Example: workmatic pause ./jobs.db emails');
|
|
478
|
+
process.exit(1);
|
|
479
|
+
}
|
|
480
|
+
await cmdPause(dbPath, positionalArgs[1]);
|
|
481
|
+
break;
|
|
482
|
+
case 'resume':
|
|
483
|
+
if (!positionalArgs[1]) {
|
|
484
|
+
console.error('Error: Queue name is required');
|
|
485
|
+
console.error('Example: workmatic resume ./jobs.db emails');
|
|
486
|
+
process.exit(1);
|
|
487
|
+
}
|
|
488
|
+
await cmdResume(dbPath, positionalArgs[1]);
|
|
489
|
+
break;
|
|
490
|
+
case 'queues':
|
|
491
|
+
await cmdQueues(dbPath);
|
|
492
|
+
break;
|
|
493
|
+
default:
|
|
494
|
+
console.error(`Unknown command: ${command}`);
|
|
495
|
+
printUsage();
|
|
496
|
+
process.exit(1);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
catch (error) {
|
|
500
|
+
console.error('Error:', error instanceof Error ? error.message : error);
|
|
501
|
+
process.exit(1);
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
main();
|
|
505
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { ClientOptions, WorkmaticClient } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Create a job queue client for adding jobs
|
|
4
|
+
*
|
|
5
|
+
* @param options - Client options
|
|
6
|
+
* @returns Client instance
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* const client = createClient({ db });
|
|
11
|
+
*
|
|
12
|
+
* // Add a simple job
|
|
13
|
+
* const result = await client.add({ email: 'user@example.com' });
|
|
14
|
+
* console.log(result.id); // Job public ID
|
|
15
|
+
*
|
|
16
|
+
* // Add a job with options
|
|
17
|
+
* await client.add(
|
|
18
|
+
* { userId: 123 },
|
|
19
|
+
* { priority: 1, delayMs: 5000, maxAttempts: 5 }
|
|
20
|
+
* );
|
|
21
|
+
*
|
|
22
|
+
* // Get queue statistics
|
|
23
|
+
* const stats = await client.stats();
|
|
24
|
+
* console.log(stats); // { ready: 5, running: 2, done: 100, ... }
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export declare function createClient(options: ClientOptions): WorkmaticClient;
|
|
28
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAEV,aAAa,EACb,eAAe,EAKhB,MAAM,YAAY,CAAC;AAGpB;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,aAAa,GAAG,eAAe,CAuFpE"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { nanoid } from 'nanoid';
|
|
2
|
+
import { sql } from 'kysely';
|
|
3
|
+
import { validatePayload, now } from './utils.js';
|
|
4
|
+
/**
|
|
5
|
+
* Create a job queue client for adding jobs
|
|
6
|
+
*
|
|
7
|
+
* @param options - Client options
|
|
8
|
+
* @returns Client instance
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* const client = createClient({ db });
|
|
13
|
+
*
|
|
14
|
+
* // Add a simple job
|
|
15
|
+
* const result = await client.add({ email: 'user@example.com' });
|
|
16
|
+
* console.log(result.id); // Job public ID
|
|
17
|
+
*
|
|
18
|
+
* // Add a job with options
|
|
19
|
+
* await client.add(
|
|
20
|
+
* { userId: 123 },
|
|
21
|
+
* { priority: 1, delayMs: 5000, maxAttempts: 5 }
|
|
22
|
+
* );
|
|
23
|
+
*
|
|
24
|
+
* // Get queue statistics
|
|
25
|
+
* const stats = await client.stats();
|
|
26
|
+
* console.log(stats); // { ready: 5, running: 2, done: 100, ... }
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export function createClient(options) {
|
|
30
|
+
const { db, queue = 'default' } = options;
|
|
31
|
+
if (!db) {
|
|
32
|
+
throw new Error('Database instance is required');
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
/**
|
|
36
|
+
* Add a job to the queue
|
|
37
|
+
*/
|
|
38
|
+
async add(payload, opts = {}) {
|
|
39
|
+
const { priority = 0, delayMs = 0, maxAttempts = 3, } = opts;
|
|
40
|
+
// Validate and serialize payload
|
|
41
|
+
const payloadJson = validatePayload(payload);
|
|
42
|
+
// Generate unique public ID
|
|
43
|
+
const publicId = nanoid();
|
|
44
|
+
const timestamp = now();
|
|
45
|
+
const runAt = timestamp + delayMs;
|
|
46
|
+
// Insert job
|
|
47
|
+
await db
|
|
48
|
+
.insertInto('workmatic_jobs')
|
|
49
|
+
.values({
|
|
50
|
+
public_id: publicId,
|
|
51
|
+
queue,
|
|
52
|
+
payload: payloadJson,
|
|
53
|
+
status: 'ready',
|
|
54
|
+
priority,
|
|
55
|
+
run_at: runAt,
|
|
56
|
+
attempts: 0,
|
|
57
|
+
max_attempts: maxAttempts,
|
|
58
|
+
lease_until: 0,
|
|
59
|
+
created_at: timestamp,
|
|
60
|
+
updated_at: timestamp,
|
|
61
|
+
last_error: null,
|
|
62
|
+
})
|
|
63
|
+
.execute();
|
|
64
|
+
return { ok: true, id: publicId };
|
|
65
|
+
},
|
|
66
|
+
/**
|
|
67
|
+
* Get job statistics for the queue
|
|
68
|
+
*/
|
|
69
|
+
async stats() {
|
|
70
|
+
const result = await db
|
|
71
|
+
.selectFrom('workmatic_jobs')
|
|
72
|
+
.select([
|
|
73
|
+
'status',
|
|
74
|
+
sql `count(*)`.as('count'),
|
|
75
|
+
])
|
|
76
|
+
.where('queue', '=', queue)
|
|
77
|
+
.groupBy('status')
|
|
78
|
+
.execute();
|
|
79
|
+
const stats = {
|
|
80
|
+
ready: 0,
|
|
81
|
+
running: 0,
|
|
82
|
+
done: 0,
|
|
83
|
+
failed: 0,
|
|
84
|
+
dead: 0,
|
|
85
|
+
total: 0,
|
|
86
|
+
};
|
|
87
|
+
for (const row of result) {
|
|
88
|
+
const status = row.status;
|
|
89
|
+
const count = Number(row.count);
|
|
90
|
+
if (status in stats) {
|
|
91
|
+
stats[status] = count;
|
|
92
|
+
}
|
|
93
|
+
stats.total += count;
|
|
94
|
+
}
|
|
95
|
+
return stats;
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,GAAG,EAAE,MAAM,QAAQ,CAAC;AAU7B,OAAO,EAAE,eAAe,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AAElD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,UAAU,YAAY,CAAC,OAAsB;IACjD,MAAM,EAAE,EAAE,EAAE,KAAK,GAAG,SAAS,EAAE,GAAG,OAAO,CAAC;IAE1C,IAAI,CAAC,EAAE,EAAE,CAAC;QACR,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;IACnD,CAAC;IAED,OAAO;QACL;;WAEG;QACH,KAAK,CAAC,GAAG,CACP,OAAiB,EACjB,OAAsB,EAAE;YAExB,MAAM,EACJ,QAAQ,GAAG,CAAC,EACZ,OAAO,GAAG,CAAC,EACX,WAAW,GAAG,CAAC,GAChB,GAAG,IAAI,CAAC;YAET,iCAAiC;YACjC,MAAM,WAAW,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;YAE7C,4BAA4B;YAC5B,MAAM,QAAQ,GAAG,MAAM,EAAE,CAAC;YAE1B,MAAM,SAAS,GAAG,GAAG,EAAE,CAAC;YACxB,MAAM,KAAK,GAAG,SAAS,GAAG,OAAO,CAAC;YAElC,aAAa;YACb,MAAM,EAAE;iBACL,UAAU,CAAC,gBAAgB,CAAC;iBAC5B,MAAM,CAAC;gBACN,SAAS,EAAE,QAAQ;gBACnB,KAAK;gBACL,OAAO,EAAE,WAAW;gBACpB,MAAM,EAAE,OAAO;gBACf,QAAQ;gBACR,MAAM,EAAE,KAAK;gBACb,QAAQ,EAAE,CAAC;gBACX,YAAY,EAAE,WAAW;gBACzB,WAAW,EAAE,CAAC;gBACd,UAAU,EAAE,SAAS;gBACrB,UAAU,EAAE,SAAS;gBACrB,UAAU,EAAE,IAAI;aACjB,CAAC;iBACD,OAAO,EAAE,CAAC;YAEb,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC;QACpC,CAAC;QAED;;WAEG;QACH,KAAK,CAAC,KAAK;YACT,MAAM,MAAM,GAAG,MAAM,EAAE;iBACpB,UAAU,CAAC,gBAAgB,CAAC;iBAC5B,MAAM,CAAC;gBACN,QAAQ;gBACR,GAAG,CAAQ,UAAU,CAAC,EAAE,CAAC,OAAO,CAAC;aAClC,CAAC;iBACD,KAAK,CAAC,OAAO,EAAE,GAAG,EAAE,KAAK,CAAC;iBAC1B,OAAO,CAAC,QAAQ,CAAC;iBACjB,OAAO,EAAE,CAAC;YAEb,MAAM,KAAK,GAAa;gBACtB,KAAK,EAAE,CAAC;gBACR,OAAO,EAAE,CAAC;gBACV,IAAI,EAAE,CAAC;gBACP,MAAM,EAAE,CAAC;gBACT,IAAI,EAAE,CAAC;gBACP,KAAK,EAAE,CAAC;aACT,CAAC;YAEF,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;gBACzB,MAAM,MAAM,GAAG,GAAG,CAAC,MAAmB,CAAC;gBACvC,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;gBAChC,IAAI,MAAM,IAAI,KAAK,EAAE,CAAC;oBACpB,KAAK,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC;gBACxB,CAAC;gBACD,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC;YACvB,CAAC;YAED,OAAO,KAAK,CAAC;QACf,CAAC;KACF,CAAC;AACJ,CAAC"}
|