Spaces:
Running
Running
File size: 4,892 Bytes
84930b1 |
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 |
from flask import Flask, render_template_string, jsonify
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 logs in real-time to both UI and terminal."""
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
)
# Stream logs to UI and print to terminal
for line in process.stdout:
log_entry['output'] += line
execution_logs.append({'time': timestamp, 'output': line, 'error': ''})
print(line, end="") # β
Print logs to terminal
if len(execution_logs) > MAX_LOG_ENTRIES:
execution_logs.pop(0)
for line in process.stderr:
log_entry['error'] += line
execution_logs.append({'time': timestamp, 'output': '', 'error': line})
print(line, end="") # β
Print errors to terminal
if len(execution_logs) > MAX_LOG_ENTRIES:
execution_logs.pop(0)
except Exception as e:
log_entry['error'] = str(e)
execution_logs.append({'time': timestamp, 'output': '', 'error': str(e)})
print(f"Error: {str(e)}") # β
Print error to terminal
def start_initial_run():
threading.Thread(target=run_cli_script, daemon=True).start()
scheduler = BackgroundScheduler(daemon=True)
scheduler.add_job(
run_cli_script,
'interval',
hours=3,
id='main_job',
next_run_time=datetime.now()
)
scheduler.start()
start_initial_run()
@app.route('/')
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>
<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()
return "Script executed manually", 200
@app.route('/run-check')
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)
|