make auto-process inbox a continuous polling loop instead of one-shot
Build and Push Docker Image / build (push) Successful in 59s
Build and Push Docker Image / build (push) Successful in 59s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
+65
-11
@@ -1101,9 +1101,8 @@ app.post("/approve-batch", async (c) => {
|
||||
let processInboxAbort: AbortController | null = null;
|
||||
|
||||
/**
|
||||
* Single entry point for launching processInbox. Manages the abort controller
|
||||
* so every caller (manual button, auto-process toggle, post-scan auto-process)
|
||||
* can be stopped via the /process-inbox/stop endpoint.
|
||||
* One-shot trigger for the manual "Process Inbox →" button. Manages the abort
|
||||
* controller so in-progress runs can be stopped via /process-inbox/stop.
|
||||
* Returns false if a run is already in progress.
|
||||
*/
|
||||
export function startProcessInbox(): boolean {
|
||||
@@ -1134,6 +1133,67 @@ export function stopProcessInbox(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
// ─── Auto-process loop ─────────────────────────────────────────────────────
|
||||
// Continuous polling loop: while enabled, checks every few seconds for
|
||||
// unsorted inbox items and processes them. The manual button is a one-shot;
|
||||
// this is the "always on" counterpart.
|
||||
const AUTO_PROCESS_POLL_MS = 5_000;
|
||||
let autoProcessTimer: Timer | null = null;
|
||||
|
||||
function scheduleAutoProcessTick() {
|
||||
if (autoProcessTimer) return;
|
||||
if (getConfig("auto_processing") !== "1") return;
|
||||
|
||||
autoProcessTimer = setTimeout(autoProcessTick, AUTO_PROCESS_POLL_MS);
|
||||
}
|
||||
|
||||
async function autoProcessTick() {
|
||||
autoProcessTimer = null;
|
||||
if (getConfig("auto_processing") !== "1") return;
|
||||
|
||||
// Don't overlap with a manual run
|
||||
if (processInboxAbort) {
|
||||
scheduleAutoProcessTick();
|
||||
return;
|
||||
}
|
||||
|
||||
const db = getDb();
|
||||
const { n } = db
|
||||
.prepare("SELECT COUNT(*) as n FROM review_plans WHERE status = 'pending' AND is_noop = 0 AND sorted = 0")
|
||||
.get() as { n: number };
|
||||
|
||||
if (n > 0) {
|
||||
processInboxAbort = new AbortController();
|
||||
const { signal } = processInboxAbort;
|
||||
|
||||
try {
|
||||
const result = await processInbox(db, getAudioLanguages(), undefined, {
|
||||
onStart: emitInboxSortStart,
|
||||
onProgress: emitInboxSortProgress,
|
||||
signal,
|
||||
});
|
||||
emitInboxSorted(result);
|
||||
} catch {
|
||||
emitInboxSorted({ moved_to_queue: 0, moved_to_review: 0 });
|
||||
} finally {
|
||||
processInboxAbort = null;
|
||||
}
|
||||
}
|
||||
|
||||
scheduleAutoProcessTick();
|
||||
}
|
||||
|
||||
export function startAutoProcessLoop() {
|
||||
scheduleAutoProcessTick();
|
||||
}
|
||||
|
||||
export function stopAutoProcessLoop() {
|
||||
if (autoProcessTimer) {
|
||||
clearTimeout(autoProcessTimer);
|
||||
autoProcessTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
app.post("/process-inbox", async (c) => {
|
||||
if (!startProcessInbox()) {
|
||||
return c.json({ ok: false, error: "processing already running" }, 409);
|
||||
@@ -1534,10 +1594,7 @@ app.post("/:id/rescan", async (c) => {
|
||||
// Delete pending jobs
|
||||
db.prepare("DELETE FROM jobs WHERE item_id = ? AND status = 'pending'").run(id);
|
||||
|
||||
// Auto-process if enabled (processInbox handles language resolution + reanalysis)
|
||||
if (getConfig("auto_processing") === "1") {
|
||||
await processInbox(db, getAudioLanguages());
|
||||
}
|
||||
// Auto-process loop (if enabled) picks up the reset item automatically.
|
||||
|
||||
emitPipelineChanged();
|
||||
return c.json({ ok: true, inInbox: true });
|
||||
@@ -1571,10 +1628,7 @@ app.post("/rescan-series", async (c) => {
|
||||
db.prepare("DELETE FROM jobs WHERE item_id = ? AND status = 'pending'").run(item.id);
|
||||
}
|
||||
|
||||
// Auto-process if enabled
|
||||
if (getConfig("auto_processing") === "1") {
|
||||
await processInbox(db, getAudioLanguages());
|
||||
}
|
||||
// Auto-process loop (if enabled) picks up reset items automatically.
|
||||
|
||||
emitPipelineChanged();
|
||||
return c.json({ ok: true, count: items.length });
|
||||
|
||||
Reference in New Issue
Block a user