Auto-commit: v2.9 — Fix background task hangs (OAuth headless guard, SQLite timeouts, log touch)
- ai/setup.py: Added threading import; OAuth block now detects background/headless threads and skips run_local_server to prevent indefinite blocking. Logs a clear warning and falls back to ADC for Vertex AI. Token file only written when creds are not None. - web/tasks.py: All sqlite3.connect() calls now use timeout=30, check_same_thread=False. OperationalError on the initial status update is caught and logged via utils.log. generate_book_task now touches initial_log immediately so the UI polling endpoint always finds an existing file even if the worker crashes on the next line. - ai_blueprint.md: Bumped to v2.9; Section 12.D sub-items 1-3 marked ✅; item 13 added to summary. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
22
web/tasks.py
22
web/tasks.py
@@ -20,7 +20,7 @@ def db_log_callback(db_path, run_id, phase, msg):
|
||||
"""Writes log entry directly to SQLite to avoid Flask Context issues in threads."""
|
||||
for _ in range(5):
|
||||
try:
|
||||
with sqlite3.connect(db_path, timeout=5) as conn:
|
||||
with sqlite3.connect(db_path, timeout=30, check_same_thread=False) as conn:
|
||||
conn.execute("INSERT INTO log_entry (run_id, timestamp, phase, message) VALUES (?, ?, ?, ?)",
|
||||
(run_id, datetime.utcnow(), phase, str(msg)))
|
||||
break
|
||||
@@ -32,7 +32,7 @@ def db_progress_callback(db_path, run_id, percent):
|
||||
"""Updates run progress in SQLite."""
|
||||
for _ in range(5):
|
||||
try:
|
||||
with sqlite3.connect(db_path, timeout=5) as conn:
|
||||
with sqlite3.connect(db_path, timeout=30, check_same_thread=False) as conn:
|
||||
conn.execute("UPDATE run SET progress = ? WHERE id = ?", (percent, run_id))
|
||||
break
|
||||
except sqlite3.OperationalError: time.sleep(0.1)
|
||||
@@ -48,6 +48,15 @@ def generate_book_task(run_id, project_path, bible_path, allow_copy=True, feedba
|
||||
|
||||
# Log to project root initially until run folder is created by engine
|
||||
initial_log = os.path.join(project_path, log_filename)
|
||||
|
||||
# Touch the file immediately so the UI has something to poll even if the
|
||||
# worker crashes before the first utils.log() call.
|
||||
try:
|
||||
with open(initial_log, 'a', encoding='utf-8') as _f:
|
||||
pass
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
utils.set_log_file(initial_log)
|
||||
|
||||
# Hook up Database Logging
|
||||
@@ -57,9 +66,12 @@ def generate_book_task(run_id, project_path, bible_path, allow_copy=True, feedba
|
||||
|
||||
# Set Status to Running
|
||||
try:
|
||||
with sqlite3.connect(db_path, timeout=10) as conn:
|
||||
with sqlite3.connect(db_path, timeout=30, check_same_thread=False) as conn:
|
||||
conn.execute("UPDATE run SET status = 'running' WHERE id = ?", (run_id,))
|
||||
except: pass
|
||||
except sqlite3.OperationalError as e:
|
||||
utils.log("SYSTEM", f"⚠️ Database locked when setting run status (run {run_id}): {e}")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
utils.log("SYSTEM", f"Starting Job #{run_id}")
|
||||
|
||||
@@ -185,7 +197,7 @@ def generate_book_task(run_id, project_path, bible_path, allow_copy=True, feedba
|
||||
|
||||
# 4. Update Database with Final Status
|
||||
try:
|
||||
with sqlite3.connect(db_path, timeout=10) as conn:
|
||||
with sqlite3.connect(db_path, timeout=30, check_same_thread=False) as conn:
|
||||
conn.execute("UPDATE run SET status = ?, cost = ?, end_time = ?, log_file = ?, progress = 100 WHERE id = ?",
|
||||
(status, total_cost, datetime.utcnow(), final_log_path, run_id))
|
||||
except Exception as e:
|
||||
|
||||
Reference in New Issue
Block a user