Skip to content

Commit 20ead33

Browse files
committed
feat: add web dashboard for monitoring
1 parent 2a3a406 commit 20ead33

1 file changed

Lines changed: 72 additions & 1 deletion

File tree

bin/queuectl.js

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -392,5 +392,76 @@ config
392392
}
393393
});
394394

395+
// Web dashboard commands
396+
const web = program.command('web').alias('app').description('Web dashboard for monitoring the job queue');
397+
web
398+
.command('start')
399+
.description('Start the web dashboard (foreground by default). Use --daemon to run in background')
400+
.option('-d, --daemon', 'Run dashboard in background')
401+
.action((opts) => {
402+
const serverScript = path.join(__dirname, '..', 'web', 'server.js');
403+
if (opts.daemon) {
404+
try {
405+
const child = spawn(process.execPath, [serverScript], {
406+
detached: true,
407+
stdio: 'ignore',
408+
cwd: process.cwd()
409+
});
410+
child.unref();
411+
412+
try {
413+
const pidFile = path.join(process.cwd(), '.dashboard.pid');
414+
//writing pid to stop app afterwards
415+
fs.writeFileSync(pidFile, String(child.pid), { encoding: 'utf8' });
416+
console.log(`[+] Dashboard started in background (pid: ${child.pid}). PID written to ${pidFile}`);
417+
} catch (e) {
418+
console.log('[+] Dashboard started in background, but failed to write PID file:', e.message);
419+
}
420+
} catch (e) {
421+
console.error('[!!] Failed to start dashboard in background:', e.message);
422+
process.exit(1);
423+
}
424+
} else {
425+
try {
426+
console.log('[*] Starting dashboard (foreground). Press CTRL+C to stop.');
427+
const fg = spawn(process.execPath, [serverScript], { stdio: 'inherit', cwd: process.cwd() });
428+
fg.on('exit', (code) => process.exit(code || 0));
429+
} catch (e) {
430+
console.error('[!!] Failed to start dashboard:', e.message);
431+
process.exit(1);
432+
}
433+
}
434+
});
435+
436+
web
437+
.command('stop')
438+
.description('Stop a dashboard started with `web start --daemon`')
439+
.action(() => {
440+
const pidFile = path.join(process.cwd(), '.dashboard.pid');
441+
if (!fs.existsSync(pidFile)) {
442+
console.error('[!] No .dashboard.pid file found in current directory — is the dashboard running?');
443+
process.exit(1);
444+
}
445+
try {
446+
const text = fs.readFileSync(pidFile, 'utf8').trim();
447+
const pid = parseInt(text, 10);
448+
if (isNaN(pid)) throw new Error('Invalid PID in pidfile');
449+
try {
450+
process.kill(pid);
451+
console.log(`[+] Sent termination signal to dashboard pid ${pid}.`);
452+
} catch (e) {
453+
// if process doesn't exist, report it but remove pidfile
454+
if (e.code === 'ESRCH') console.warn('[!] No process found with that PID — removing stale pidfile.');
455+
else throw e;
456+
}
457+
try { fs.unlinkSync(pidFile); } catch (e) {}
458+
process.exit(0);
459+
} catch (e) {
460+
console.error('[!!] Failed to stop dashboard:', e.message);
461+
process.exit(1);
462+
}
463+
});
464+
395465
printBanner();
396-
program.parse(process.argv);
466+
program.parse(process.argv);
467+

0 commit comments

Comments
 (0)