From a438493a76e6400ba925141a852cb875a61341f1 Mon Sep 17 00:00:00 2001 From: nmemmert <67961292+nmemmert@users.noreply.github.com> Date: Fri, 7 Nov 2025 07:59:41 -0500 Subject: [PATCH] job persitance andupdates --- __pycache__/pdf_renamer.cpython-313.pyc | Bin 64931 -> 71676 bytes pdf_renamer.py | 65 +++++++++++++++++++++++- 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/__pycache__/pdf_renamer.cpython-313.pyc b/__pycache__/pdf_renamer.cpython-313.pyc index 6778704503cc25a76b78c5018afe21ce75d16d3a..74a68fe4c67b25a10882262e7f9545df973c1378 100644 GIT binary patch delta 14775 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 diff --git a/pdf_renamer.py b/pdf_renamer.py index cf5a307..013812f 100644 --- a/pdf_renamer.py +++ b/pdf_renamer.py @@ -3,6 +3,7 @@ import tempfile import zipfile import threading import uuid +import json from datetime import datetime from functools import wraps from flask import Flask, request, render_template_string, redirect, url_for, session, send_from_directory, flash, get_flashed_messages, jsonify @@ -54,6 +55,56 @@ except Exception as e: print(f"ERROR: Failed to register Microsoft OAuth provider: {e}") microsoft = None +# Job persistence +JOBS_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'jobs.json') +job_queue = {} +job_lock = threading.Lock() + +def save_jobs(): + """Save jobs to persistent storage""" + try: + with job_lock: + # Convert datetime objects to strings for JSON serialization + jobs_to_save = {} + for job_id, job in job_queue.items(): + jobs_to_save[job_id] = job.copy() + # Convert any datetime objects if needed + if 'created_at' in jobs_to_save[job_id]: + jobs_to_save[job_id]['created_at'] = str(jobs_to_save[job_id]['created_at']) + + with open(JOBS_FILE, 'w') as f: + json.dump(jobs_to_save, f, indent=2) + except Exception as e: + print(f"ERROR: Failed to save jobs: {e}") + +def load_jobs(): + """Load jobs from persistent storage""" + global job_queue + try: + if os.path.exists(JOBS_FILE): + with open(JOBS_FILE, 'r') as f: + loaded_jobs = json.load(f) + job_queue = loaded_jobs + print(f"DEBUG: Loaded {len(job_queue)} jobs from persistent storage") + else: + print("DEBUG: No existing jobs file found, starting fresh") + except Exception as e: + print(f"ERROR: Failed to load jobs: {e}") + job_queue = {} + +# Load jobs on startup +load_jobs() + +def update_job_status(job_id, status, **kwargs): + """Update job status and persist changes""" + with job_lock: + if job_id in job_queue: + job_queue[job_id]['status'] = status + job_queue[job_id].update(kwargs) + job_queue[job_id]['updated_at'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S') + save_jobs() + print(f"DEBUG: Job {job_id} status updated to {status}") + def analyze_failed_extractions(log_path): """ Analyze failed extraction log to identify new patterns. @@ -459,6 +510,7 @@ def process_job(job_id, files): print("=== DEBUG: process_job STARTED ===") job_queue[job_id]['status'] = 'processing' job_queue[job_id]['progress'] = 'Starting job processing...' + save_jobs() # Persist status change processed_files = [] temp_extract_dirs = [] @@ -614,6 +666,7 @@ def process_job(job_id, files): except Exception as e: job_queue[job_id]['progress'] = f'Error creating ZIP: {str(e)}' job_queue[job_id]['status'] = 'error' + save_jobs() # Persist error status print(f"DEBUG: ZIP creation failed: {str(e)}") else: job_queue[job_id]['progress'] = 'No files to archive - all files were skipped' @@ -622,11 +675,13 @@ def process_job(job_id, files): job_queue[job_id]['status'] = 'completed' job_queue[job_id]['processed_files'] = processed_files job_queue[job_id]['skipped'] = [(p[1], p[2]) for p in processed_files if p[0] == 'skipped'] + save_jobs() # Persist completed job print(f"DEBUG: Job {job_id} completed successfully. Processed: {len(processed_files)}, Skipped: {len(job_queue[job_id]['skipped'])}") except Exception as e: job_queue[job_id]['status'] = 'error' job_queue[job_id]['progress'] = f'Job failed with error: {str(e)}' + save_jobs() # Persist error status print(f"Job {job_id} failed: {str(e)}") # Debug logging @app.route('/login') @@ -776,7 +831,8 @@ def upload_files(): flash('No files selected.', 'error') return redirect(url_for('upload_files')) - job_id = str(uuid.uuid4()) + # Create job ID using timestamp format: YYYY-MM-DD_HH-MM-SS + job_id = datetime.now().strftime('%Y-%m-%d_%H-%M-%S') job_queue[job_id] = { 'status': 'queued', 'files': [], @@ -784,7 +840,8 @@ def upload_files(): 'zip_name': None, 'processed_files': [], 'skipped': [], - 'created_at': datetime.now().strftime('%Y-%m-%d %H:%M:%S') + 'created_at': datetime.now().strftime('%Y-%m-%d %H:%M:%S'), + 'job_id': job_id # Store the job ID for reference } file_list = [] @@ -804,6 +861,9 @@ def upload_files(): job_queue[job_id]['files'] = file_list print(f"Created job {job_id} with {len(file_list)} files") # Debug logging + # Save job to persistent storage + save_jobs() + # Start processing in background def process_with_context(): with app.app_context(): @@ -1109,6 +1169,7 @@ def delete_job(job_id): os.remove(zip_path) # Remove the job from the queue del job_queue[job_id] + save_jobs() # Persist job deletion flash('Job deleted successfully.', 'success') else: flash('Only completed jobs can be deleted.', 'error')