#!/usr/bin/env python3 """ Emergency force stop utility for the scraper. This script will: 1. Set the scraper state to inactive 2. Revoke all running/scheduled tasks 3. Purge task queues 4. Revert any papers in "Pending" state to their previous status Use this to recover from a misbehaving scraper or when the web UI is unresponsive. """ import os import sys import time from datetime import datetime # Add project root to path sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../..'))) # Import required modules from scipaperloader import create_app from scipaperloader.db import db from scipaperloader.models import PaperMetadata, ActivityLog, ScraperState app = create_app() def emergency_stop(): """Force stop the scraper and revert all pending papers""" with app.app_context(): print("Emergency Scraper Stop") print("-" * 50) # 1. Set scraper state to inactive ScraperState.set_active(False) ScraperState.set_paused(False) print("✓ Set scraper state to inactive") # 2. Revoke all jobs in APScheduler scheduler = app.config.get('SCHEDULER') if scheduler: revoked_count = scheduler.revoke_all_scraper_jobs() print(f"✅ Revoked {revoked_count} jobs from APScheduler") else: print("❌ APScheduler not found in app config") # 3. Revert all papers to 'Pending' state PaperMetadata.query.filter_by(status="Processing").update({"status": "Pending"}) db.session.commit() print("✅ Reverted all 'Processing' papers to 'Pending' state") # 4. Revert papers in "Pending" status try: print("\nReverting papers from 'Pending' status...") pending_papers = PaperMetadata.query.filter_by(status="Pending").all() reverted_count = 0 for paper in pending_papers: # Get previous status or use "New" as fallback previous_status = paper.previous_status if hasattr(paper, 'previous_status') and paper.previous_status else "New" paper.status = previous_status ActivityLog.log_scraper_activity( action="emergency_revert", paper_id=paper.id, status="info", description=f"Emergency reversion from 'Pending' to '{previous_status}'", ) reverted_count += 1 print(f" Reverted paper ID {paper.id}: {paper.title} -> {previous_status}") # Commit changes db.session.commit() print(f"✓ Reverted {reverted_count} papers") ActivityLog.log_scraper_command( action="emergency_stop", status="success", description=f"Emergency stop performed. Revoked {revoked_count} tasks and reverted {reverted_count} papers." ) except Exception as e: db.session.rollback() print(f"⚠ Error reverting papers: {str(e)}") print("\nEmergency stop completed!") print(f"Current time: {datetime.now()}") if __name__ == "__main__": emergency_stop()