Spaces:
Runtime error
Runtime error
File size: 5,449 Bytes
14b7018 e96a62a 88e9f1a aa456fd 2a6e962 5c6037b e96a62a 2a6e962 e96a62a 2a6e962 3a2ce2a 2a6e962 5c6037b aa456fd 2a6e962 aa456fd 2a6e962 87175db e96a62a 87175db 5c6037b 87175db 2a6e962 5c6037b 87175db 2a6e962 87175db 5c6037b 2a6e962 e96a62a 88e9f1a 2a6e962 88e9f1a 2a6e962 cd03aa3 88e9f1a cd03aa3 88e9f1a 2a6e962 88e9f1a e96a62a 2a6e962 e96a62a 88e9f1a cd03aa3 2a6e962 de50ad7 5c6037b de50ad7 14b7018 de50ad7 5c6037b 3a2ce2a 5c6037b 3a2ce2a 5c6037b 88e9f1a 5c6037b 3a2ce2a 5c6037b 3a2ce2a cd03aa3 3a2ce2a de50ad7 cd03aa3 88e9f1a 5c6037b de50ad7 5c6037b 2a6e962 14b7018 2a6e962 3a2ce2a 88e9f1a 2a6e962 3a2ce2a e96a62a 2a6e962 88e9f1a 2a6e962 88e9f1a 2a6e962 88e9f1a 2a6e962 88e9f1a 2a6e962 e96a62a 14b7018 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
from flask import Flask, render_template_string, jsonify
from apscheduler.schedulers.background import BackgroundScheduler
import subprocess
import threading
import pytz
import logging
from datetime import datetime
# Initialize Flask app
app = Flask(__name__)
# Setup logging
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
# Execution logs
execution_logs = []
MAX_LOG_ENTRIES = 50
log_lock = threading.Lock() # Prevents race conditions when modifying logs
def add_log_entry(entry):
"""Safely add log entries while maintaining MAX_LOG_ENTRIES limit."""
with log_lock:
execution_logs.append(entry)
if len(execution_logs) > MAX_LOG_ENTRIES:
execution_logs.pop(0)
def get_ist_time():
"""Get the current time in IST (Indian Standard Time)."""
utc_now = datetime.utcnow()
ist_timezone = pytz.timezone("Asia/Kolkata")
return utc_now.replace(tzinfo=pytz.utc).astimezone(ist_timezone)
def run_cli_script():
"""Runs cli.py and streams logs in real-time to both UI and terminal."""
timestamp = get_ist_time().strftime("%Y-%m-%d %H:%M:%S IST")
try:
process = subprocess.Popen(
["python", "cli.py"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True
)
stdout, stderr = process.communicate() # Wait for process to complete
if stdout:
add_log_entry({'time': timestamp, 'output': stdout, 'error': ''})
logging.info(stdout.strip())
if stderr:
add_log_entry({'time': timestamp, 'output': '', 'error': stderr})
logging.error(stderr.strip())
except Exception as e:
error_msg = str(e)
add_log_entry({'time': timestamp, 'output': '', 'error': error_msg})
logging.error(f"Error: {error_msg}")
def start_initial_run():
"""Runs the CLI script immediately upon startup in a separate thread."""
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()
# Ensure script runs once on startup
start_initial_run()
@app.route('/')
def home():
"""Main UI displaying logs and next run time."""
job = scheduler.get_job('main_job')
next_run = get_ist_time().strftime('%Y-%m-%d %H:%M:%S IST') if job else 'N/A'
return render_template_string('''
<!DOCTYPE html>
<html>
<head>
<title>Script Scheduler</title>
<script>
function fetchLogs() {
fetch('/logs')
.then(response => response.json())
.then(data => {
let logBox = document.getElementById("log-box");
logBox.innerHTML = "";
data.logs.forEach(log => {
let logEntry = "<div class='timestamp'>" + log.time + "</div>";
if (log.output) logEntry += "<div class='output'>" + log.output + "</div>";
if (log.error) logEntry += "<div class='error'>" + log.error + "</div>";
logEntry += "<hr>";
logBox.innerHTML += logEntry;
});
logBox.scrollTop = logBox.scrollHeight;
});
}
setInterval(fetchLogs, 2000);
window.onload = fetchLogs;
</script>
<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 id="log-box" class="log-box"></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)
@app.route('/logs')
def logs():
"""Returns logs as JSON for AJAX polling."""
return jsonify({'logs': execution_logs})
@app.route('/force-run')
def force_run():
"""Manually trigger the script execution."""
threading.Thread(target=run_cli_script, daemon=True).start()
logging.info("Manual script execution triggered")
return "Script executed manually", 200
@app.route('/run-check')
def run_check():
"""Check if the scheduler is still running and restart if necessary."""
if not scheduler.running:
logging.warning("Scheduler was stopped! Restarting...")
scheduler.start()
return "Scheduler restarted", 200
return "Scheduler is running", 200
if __name__ == '__main__':
app.run(host='0.0.0.0', port=7860)
|