specrails-hub 1.25.5 → 1.26.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/package.json
CHANGED
|
@@ -90,9 +90,21 @@ class ProjectRegistry {
|
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
92
|
};
|
|
93
|
+
// Per-project zombie timeout (stored in queue_state)
|
|
94
|
+
let projectZombieTimeout;
|
|
95
|
+
try {
|
|
96
|
+
const row = db.prepare(`SELECT value FROM queue_state WHERE key = 'config.zombie_timeout_ms'`).get();
|
|
97
|
+
if (row) {
|
|
98
|
+
const parsed = parseInt(row.value, 10);
|
|
99
|
+
if (!isNaN(parsed) && parsed > 0)
|
|
100
|
+
projectZombieTimeout = parsed;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
catch { /* queue_state table may not exist yet */ }
|
|
93
104
|
const webhookManager = this._webhookManager;
|
|
94
105
|
const railJobs = new Map();
|
|
95
106
|
const queueManager = new queue_manager_1.QueueManager(boundBroadcast, db, undefined, project.path, {
|
|
107
|
+
zombieTimeoutMs: projectZombieTimeout,
|
|
96
108
|
provider: project.provider ?? 'claude',
|
|
97
109
|
getCostAlertThreshold: () => {
|
|
98
110
|
const val = (0, hub_db_1.getHubSetting)(this._hubDb, 'cost_alert_threshold_usd');
|
|
@@ -454,7 +454,9 @@ function createProjectRouter(registry) {
|
|
|
454
454
|
const config = (0, config_1.getConfig)(project.path, db, project.name);
|
|
455
455
|
const dailyBudgetRaw = db.prepare(`SELECT value FROM queue_state WHERE key = 'config.daily_budget_usd'`).get()?.value;
|
|
456
456
|
const dailyBudgetUsd = dailyBudgetRaw != null ? parseFloat(dailyBudgetRaw) : null;
|
|
457
|
-
|
|
457
|
+
const zombieTimeoutRaw = db.prepare(`SELECT value FROM queue_state WHERE key = 'config.zombie_timeout_ms'`).get()?.value;
|
|
458
|
+
const zombieTimeoutMs = zombieTimeoutRaw != null ? parseInt(zombieTimeoutRaw, 10) : null;
|
|
459
|
+
res.json({ ...config, dailyBudgetUsd, zombieTimeoutMs });
|
|
458
460
|
}
|
|
459
461
|
catch (err) {
|
|
460
462
|
console.error('[project-router] config error:', err);
|
|
@@ -462,8 +464,8 @@ function createProjectRouter(registry) {
|
|
|
462
464
|
}
|
|
463
465
|
});
|
|
464
466
|
router.post('/:projectId/config', (req, res) => {
|
|
465
|
-
const { active, labelFilter, dailyBudgetUsd } = req.body ?? {};
|
|
466
|
-
const { db } = ctx(req);
|
|
467
|
+
const { active, labelFilter, dailyBudgetUsd, zombieTimeoutMs } = req.body ?? {};
|
|
468
|
+
const { db, queueManager } = ctx(req);
|
|
467
469
|
try {
|
|
468
470
|
if (active !== undefined) {
|
|
469
471
|
db.prepare(`INSERT OR REPLACE INTO queue_state (key, value) VALUES ('config.active_tracker', ?)`).run(active ?? '');
|
|
@@ -479,6 +481,15 @@ function createProjectRouter(registry) {
|
|
|
479
481
|
db.prepare(`INSERT OR REPLACE INTO queue_state (key, value) VALUES ('config.daily_budget_usd', ?)`).run(String(dailyBudgetUsd));
|
|
480
482
|
}
|
|
481
483
|
}
|
|
484
|
+
if (zombieTimeoutMs !== undefined) {
|
|
485
|
+
if (zombieTimeoutMs === null) {
|
|
486
|
+
db.prepare(`DELETE FROM queue_state WHERE key = 'config.zombie_timeout_ms'`).run();
|
|
487
|
+
}
|
|
488
|
+
else if (typeof zombieTimeoutMs === 'number' && zombieTimeoutMs > 0) {
|
|
489
|
+
db.prepare(`INSERT OR REPLACE INTO queue_state (key, value) VALUES ('config.zombie_timeout_ms', ?)`).run(String(zombieTimeoutMs));
|
|
490
|
+
}
|
|
491
|
+
queueManager.setZombieTimeout(typeof zombieTimeoutMs === 'number' && zombieTimeoutMs > 0 ? zombieTimeoutMs : queue_manager_1.DEFAULT_ZOMBIE_TIMEOUT_MS);
|
|
492
|
+
}
|
|
482
493
|
res.json({ ok: true });
|
|
483
494
|
}
|
|
484
495
|
catch (err) {
|
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.QueueManager = exports.JobAlreadyTerminalError = exports.JobNotFoundError = exports.CodexNotFoundError = exports.ClaudeNotFoundError = void 0;
|
|
6
|
+
exports.QueueManager = exports.JobAlreadyTerminalError = exports.JobNotFoundError = exports.CodexNotFoundError = exports.ClaudeNotFoundError = exports.DEFAULT_ZOMBIE_TIMEOUT_MS = void 0;
|
|
7
7
|
const child_process_1 = require("child_process");
|
|
8
8
|
const readline_1 = require("readline");
|
|
9
9
|
const uuid_1 = require("uuid");
|
|
@@ -14,7 +14,7 @@ const hooks_1 = require("./hooks");
|
|
|
14
14
|
const db_1 = require("./db");
|
|
15
15
|
const LOG_BUFFER_MAX = 5000;
|
|
16
16
|
const LOG_BUFFER_DROP = 1000;
|
|
17
|
-
|
|
17
|
+
exports.DEFAULT_ZOMBIE_TIMEOUT_MS = 1_800_000; // 30 minutes
|
|
18
18
|
// ─── Error classes ────────────────────────────────────────────────────────────
|
|
19
19
|
class ClaudeNotFoundError extends Error {
|
|
20
20
|
constructor() {
|
|
@@ -127,7 +127,7 @@ class QueueManager {
|
|
|
127
127
|
? parseInt(process.env.WM_ZOMBIE_TIMEOUT_MS, 10)
|
|
128
128
|
: null;
|
|
129
129
|
this._zombieTimeoutMs = options?.zombieTimeoutMs
|
|
130
|
-
?? (envTimeout !== null && !isNaN(envTimeout) ? envTimeout : DEFAULT_ZOMBIE_TIMEOUT_MS);
|
|
130
|
+
?? (envTimeout !== null && !isNaN(envTimeout) ? envTimeout : exports.DEFAULT_ZOMBIE_TIMEOUT_MS);
|
|
131
131
|
if (this._db) {
|
|
132
132
|
this._restoreFromDb();
|
|
133
133
|
}
|
|
@@ -135,6 +135,13 @@ class QueueManager {
|
|
|
135
135
|
setCommands(commands) {
|
|
136
136
|
this._commands = commands;
|
|
137
137
|
}
|
|
138
|
+
setZombieTimeout(ms) {
|
|
139
|
+
this._zombieTimeoutMs = ms;
|
|
140
|
+
// If a job is currently running, reset the timer with the new value
|
|
141
|
+
if (this._activeJobId) {
|
|
142
|
+
this._resetZombieTimer();
|
|
143
|
+
}
|
|
144
|
+
}
|
|
138
145
|
// ─── Public API ─────────────────────────────────────────────────────────────
|
|
139
146
|
enqueue(command, priorityOrOpts, opts) {
|
|
140
147
|
// Support both: enqueue(cmd, priority, opts) and enqueue(cmd, opts)
|