Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
| 1 |
from flask import Flask, render_template_string
|
| 2 |
from apscheduler.schedulers.background import BackgroundScheduler
|
| 3 |
import subprocess
|
|
|
|
| 4 |
from datetime import datetime
|
| 5 |
|
| 6 |
app = Flask(__name__)
|
|
@@ -8,6 +9,7 @@ execution_logs = []
|
|
| 8 |
MAX_LOG_ENTRIES = 20
|
| 9 |
|
| 10 |
def run_cli_script():
|
|
|
|
| 11 |
timestamp = datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S UTC")
|
| 12 |
log_entry = {'time': timestamp, 'output': '', 'error': ''}
|
| 13 |
|
|
@@ -18,8 +20,8 @@ def run_cli_script():
|
|
| 18 |
text=True,
|
| 19 |
timeout=300
|
| 20 |
)
|
| 21 |
-
log_entry['output'] = result.stdout
|
| 22 |
-
log_entry['error'] = result.stderr
|
| 23 |
except Exception as e:
|
| 24 |
log_entry['error'] = str(e)
|
| 25 |
finally:
|
|
@@ -27,21 +29,27 @@ def run_cli_script():
|
|
| 27 |
if len(execution_logs) > MAX_LOG_ENTRIES:
|
| 28 |
execution_logs.pop(0)
|
| 29 |
|
| 30 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
| 31 |
scheduler = BackgroundScheduler(daemon=True)
|
| 32 |
scheduler.add_job(
|
| 33 |
run_cli_script,
|
| 34 |
'interval',
|
| 35 |
hours=3,
|
| 36 |
id='main_job',
|
| 37 |
-
next_run_time=datetime.now()
|
| 38 |
)
|
| 39 |
scheduler.start()
|
| 40 |
-
|
|
|
|
|
|
|
| 41 |
|
| 42 |
@app.route('/')
|
| 43 |
def home():
|
| 44 |
-
|
| 45 |
job = scheduler.get_job('main_job')
|
| 46 |
next_run = job.next_run_time.strftime('%Y-%m-%d %H:%M:%S UTC') if job else 'N/A'
|
| 47 |
|
|
@@ -60,6 +68,8 @@ def home():
|
|
| 60 |
border-radius: 5px;
|
| 61 |
margin-top: 20px;
|
| 62 |
white-space: pre-wrap;
|
|
|
|
|
|
|
| 63 |
}
|
| 64 |
.timestamp { color: #888; margin-bottom: 10px; }
|
| 65 |
.error { color: #ff4444; }
|
|
@@ -84,14 +94,24 @@ def home():
|
|
| 84 |
{% endfor %}
|
| 85 |
</div>
|
| 86 |
<p><a href="/force-run">Trigger Manual Run</a></p>
|
|
|
|
| 87 |
</body>
|
| 88 |
</html>
|
| 89 |
''', next_run=next_run, logs=execution_logs)
|
| 90 |
|
| 91 |
@app.route('/force-run')
|
| 92 |
def force_run():
|
| 93 |
-
|
|
|
|
| 94 |
return "Script executed manually", 200
|
| 95 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 96 |
if __name__ == '__main__':
|
| 97 |
-
app.run(host='0.0.0.0', port=7860)
|
|
|
|
| 1 |
from flask import Flask, render_template_string
|
| 2 |
from apscheduler.schedulers.background import BackgroundScheduler
|
| 3 |
import subprocess
|
| 4 |
+
import threading
|
| 5 |
from datetime import datetime
|
| 6 |
|
| 7 |
app = Flask(__name__)
|
|
|
|
| 9 |
MAX_LOG_ENTRIES = 20
|
| 10 |
|
| 11 |
def run_cli_script():
|
| 12 |
+
"""Executes cli.py and stores logs."""
|
| 13 |
timestamp = datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S UTC")
|
| 14 |
log_entry = {'time': timestamp, 'output': '', 'error': ''}
|
| 15 |
|
|
|
|
| 20 |
text=True,
|
| 21 |
timeout=300
|
| 22 |
)
|
| 23 |
+
log_entry['output'] = result.stdout.strip()
|
| 24 |
+
log_entry['error'] = result.stderr.strip()
|
| 25 |
except Exception as e:
|
| 26 |
log_entry['error'] = str(e)
|
| 27 |
finally:
|
|
|
|
| 29 |
if len(execution_logs) > MAX_LOG_ENTRIES:
|
| 30 |
execution_logs.pop(0)
|
| 31 |
|
| 32 |
+
# Start script in a separate thread to avoid blocking Flask
|
| 33 |
+
def start_initial_run():
|
| 34 |
+
threading.Thread(target=run_cli_script, daemon=True).start()
|
| 35 |
+
|
| 36 |
+
# Initialize scheduler
|
| 37 |
scheduler = BackgroundScheduler(daemon=True)
|
| 38 |
scheduler.add_job(
|
| 39 |
run_cli_script,
|
| 40 |
'interval',
|
| 41 |
hours=3,
|
| 42 |
id='main_job',
|
| 43 |
+
next_run_time=datetime.now()
|
| 44 |
)
|
| 45 |
scheduler.start()
|
| 46 |
+
|
| 47 |
+
# Run the script asynchronously to prevent blocking
|
| 48 |
+
start_initial_run()
|
| 49 |
|
| 50 |
@app.route('/')
|
| 51 |
def home():
|
| 52 |
+
"""Main UI displaying logs and next run time."""
|
| 53 |
job = scheduler.get_job('main_job')
|
| 54 |
next_run = job.next_run_time.strftime('%Y-%m-%d %H:%M:%S UTC') if job else 'N/A'
|
| 55 |
|
|
|
|
| 68 |
border-radius: 5px;
|
| 69 |
margin-top: 20px;
|
| 70 |
white-space: pre-wrap;
|
| 71 |
+
max-height: 400px;
|
| 72 |
+
overflow-y: auto;
|
| 73 |
}
|
| 74 |
.timestamp { color: #888; margin-bottom: 10px; }
|
| 75 |
.error { color: #ff4444; }
|
|
|
|
| 94 |
{% endfor %}
|
| 95 |
</div>
|
| 96 |
<p><a href="/force-run">Trigger Manual Run</a></p>
|
| 97 |
+
<p><a href="/run-check">Check Scheduler Status</a></p>
|
| 98 |
</body>
|
| 99 |
</html>
|
| 100 |
''', next_run=next_run, logs=execution_logs)
|
| 101 |
|
| 102 |
@app.route('/force-run')
|
| 103 |
def force_run():
|
| 104 |
+
"""Manually trigger the script execution."""
|
| 105 |
+
threading.Thread(target=run_cli_script, daemon=True).start()
|
| 106 |
return "Script executed manually", 200
|
| 107 |
|
| 108 |
+
@app.route('/run-check')
|
| 109 |
+
def run_check():
|
| 110 |
+
"""Check if the scheduler is still running."""
|
| 111 |
+
if not scheduler.running:
|
| 112 |
+
print("Scheduler was stopped! Restarting...")
|
| 113 |
+
scheduler.start()
|
| 114 |
+
return "Scheduler is running", 200
|
| 115 |
+
|
| 116 |
if __name__ == '__main__':
|
| 117 |
+
app.run(host='0.0.0.0', port=7860)
|