Spaces:
Runtime error
Runtime error
| from flask import Flask, render_template_string | |
| from apscheduler.schedulers.background import BackgroundScheduler | |
| import subprocess | |
| import threading | |
| from datetime import datetime | |
| app = Flask(__name__) | |
| execution_logs = [] | |
| MAX_LOG_ENTRIES = 20 | |
| def run_cli_script(): | |
| """Runs cli.py and streams the output in real-time.""" | |
| timestamp = datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S UTC") | |
| log_entry = {'time': timestamp, 'output': '', 'error': ''} | |
| try: | |
| process = subprocess.Popen( | |
| ["python", "cli.py"], | |
| stdout=subprocess.PIPE, | |
| stderr=subprocess.PIPE, | |
| text=True, | |
| bufsize=1 # Ensures line buffering (real-time output) | |
| ) | |
| # Stream stdout in real-time | |
| for line in process.stdout: | |
| log_entry['output'] += line | |
| print(line, end="") # Also print to terminal for debugging | |
| # Capture errors in real-time | |
| for line in process.stderr: | |
| log_entry['error'] += line | |
| print(line, end="") # Also print to terminal for debugging | |
| except Exception as e: | |
| log_entry['error'] = str(e) | |
| finally: | |
| execution_logs.append(log_entry) | |
| if len(execution_logs) > MAX_LOG_ENTRIES: | |
| execution_logs.pop(0) | |
| # Start script in a separate thread to avoid blocking Flask | |
| def start_initial_run(): | |
| threading.Thread(target=run_cli_script, daemon=True).start() | |
| # Initialize scheduler | |
| scheduler = BackgroundScheduler(daemon=True) | |
| scheduler.add_job( | |
| run_cli_script, | |
| 'interval', | |
| hours=3, | |
| id='main_job', | |
| next_run_time=datetime.now() | |
| ) | |
| scheduler.start() | |
| # Run the script asynchronously to prevent blocking | |
| start_initial_run() | |
| def home(): | |
| """Main UI displaying logs and next run time.""" | |
| job = scheduler.get_job('main_job') | |
| next_run = job.next_run_time.strftime('%Y-%m-%d %H:%M:%S UTC') if job else 'N/A' | |
| return render_template_string(''' | |
| <!DOCTYPE html> | |
| <html> | |
| <head> | |
| <title>Script Scheduler</title> | |
| <meta http-equiv="refresh" content="10"> | |
| <style> | |
| body { font-family: Arial, sans-serif; padding: 20px; } | |
| .log-box { | |
| background: #000; | |
| color: #0f0; | |
| padding: 15px; | |
| border-radius: 5px; | |
| margin-top: 20px; | |
| white-space: pre-wrap; | |
| max-height: 400px; | |
| overflow-y: auto; | |
| } | |
| .timestamp { color: #888; margin-bottom: 10px; } | |
| .error { color: #ff4444; } | |
| </style> | |
| </head> | |
| <body> | |
| <h1>Script Scheduler</h1> | |
| <p>Next run: {{ next_run }}</p> | |
| <h2>Latest Execution Logs</h2> | |
| <div class="log-box"> | |
| {% for log in logs|reverse %} | |
| <div class="timestamp">{{ log.time }}</div> | |
| {% if log.output %} | |
| <div class="output">{{ log.output }}</div> | |
| {% endif %} | |
| {% if log.error %} | |
| <div class="error">{{ log.error }}</div> | |
| {% endif %} | |
| <hr> | |
| {% else %} | |
| <div>No logs available yet</div> | |
| {% endfor %} | |
| </div> | |
| <p><a href="/force-run">Trigger Manual Run</a></p> | |
| <p><a href="/run-check">Check Scheduler Status</a></p> | |
| </body> | |
| </html> | |
| ''', next_run=next_run, logs=execution_logs) | |
| def force_run(): | |
| """Manually trigger the script execution.""" | |
| threading.Thread(target=run_cli_script, daemon=True).start() | |
| return "Script executed manually", 200 | |
| def run_check(): | |
| """Check if the scheduler is still running.""" | |
| if not scheduler.running: | |
| print("Scheduler was stopped! Restarting...") | |
| scheduler.start() | |
| return "Scheduler is running", 200 | |
| if __name__ == '__main__': | |
| app.run(host='0.0.0.0', port=7860) | |