diff --git a/web/tasks.py b/web/tasks.py index 7796c4e..d2d2d69 100644 --- a/web/tasks.py +++ b/web/tasks.py @@ -107,6 +107,56 @@ def generate_book_task(run_id, project_path, bible_path, allow_copy=True, feedba _task_log(f"Task picked up by Huey worker. project_path={project_path}") + # 0. Orphaned Job Guard — verify that all required resources exist before + # doing any work. If a run, project folder, or bible is missing, terminate + # silently and mark the run as failed to prevent data being written to the + # wrong book or project. + db_path_early = os.path.join(config.DATA_DIR, "bookapp.db") + + try: + with sqlite3.connect(db_path_early, timeout=10) as _conn: + _row = _conn.execute("SELECT id FROM run WHERE id = ?", (run_id,)).fetchone() + if not _row: + _task_log(f"ABORT: Run #{run_id} no longer exists in DB. Terminating silently.") + return + except Exception as _e: + _task_log(f"WARNING: Could not verify run #{run_id} existence: {_e}") + + if not os.path.isdir(project_path): + _task_log(f"ABORT: Project folder missing ({project_path}). Marking run #{run_id} as failed.") + try: + _robust_update_run_status(db_path_early, run_id, 'failed', + end_time=datetime.utcnow().isoformat()) + except Exception: pass + return + + if not os.path.isfile(bible_path): + _task_log(f"ABORT: Bible file missing ({bible_path}). Marking run #{run_id} as failed.") + try: + _robust_update_run_status(db_path_early, run_id, 'failed', + end_time=datetime.utcnow().isoformat()) + except Exception: pass + return + + # Validate that the bible has at least one book entry + try: + with open(bible_path, 'r', encoding='utf-8') as _bf: + _bible_check = json.load(_bf) + if not _bible_check.get('books'): + _task_log(f"ABORT: Bible has no books defined. Marking run #{run_id} as failed.") + try: + _robust_update_run_status(db_path_early, run_id, 'failed', + end_time=datetime.utcnow().isoformat()) + except Exception: pass + return + except Exception as _e: + _task_log(f"ABORT: Could not parse bible ({bible_path}): {_e}. Marking run #{run_id} as failed.") + try: + _robust_update_run_status(db_path_early, run_id, 'failed', + end_time=datetime.utcnow().isoformat()) + except Exception: pass + return + # 1. Setup Logging log_filename = f"system_log_{run_id}.txt"