imseldrith commited on
Commit
7594a64
·
verified ·
1 Parent(s): 241129c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +35 -66
app.py CHANGED
@@ -2,79 +2,45 @@ from flask import Flask, render_template_string, jsonify
2
  from apscheduler.schedulers.background import BackgroundScheduler
3
  import subprocess
4
  import threading
5
- import pytz
6
  from datetime import datetime
7
- from io import TextIOWrapper
8
 
9
  app = Flask(__name__)
10
  execution_logs = []
11
- MAX_LOG_ENTRIES = 20 # Now tracks executions, not individual lines
12
- log_lock = threading.Lock() # Thread safety for execution_logs
13
- process_lock = threading.Lock() # Prevent concurrent script execution
14
 
15
  def run_cli_script():
16
- """Runs cli.py and captures output/errors into a single log entry."""
17
- if not process_lock.acquire(blocking=False):
18
- # Another instance is already running
19
- return
20
 
21
  try:
22
- # Get current time in IST
23
- utc_now = datetime.utcnow()
24
- ist = pytz.timezone("Asia/Kolkata")
25
- timestamp = utc_now.replace(tzinfo=pytz.utc).astimezone(ist).strftime("%Y-%m-%d %H:%M:%S IST")
26
-
27
- log_entry = {'time': timestamp, 'output': '', 'error': ''}
28
-
29
- with subprocess.Popen(
30
  ["python", "cli.py"],
31
  stdout=subprocess.PIPE,
32
  stderr=subprocess.PIPE,
33
- bufsize=1,
34
- text=True
35
- ) as process:
36
- # Thread function to capture output
37
- def capture_stream(stream, type):
38
- for line in stream:
39
- if type == 'output':
40
- log_entry['output'] += line
41
- print(line, end='')
42
- else:
43
- log_entry['error'] += line
44
- print(line, end='', file=sys.stderr)
45
-
46
- # Start threads to capture stdout and stderr
47
- stdout_thread = threading.Thread(
48
- target=capture_stream,
49
- args=(process.stdout, 'output')
50
- )
51
- stderr_thread = threading.Thread(
52
- target=capture_stream,
53
- args=(process.stderr, 'error')
54
- )
55
- stdout_thread.start()
56
- stderr_thread.start()
57
-
58
- # Wait for process to complete or timeout (e.g., 1 hour)
59
- process.wait(timeout=3600)
60
-
61
- # Wait for threads to finish
62
- stdout_thread.join()
63
- stderr_thread.join()
64
 
65
- # Add completed log entry
66
- with log_lock:
67
- execution_logs.append(log_entry)
 
68
  if len(execution_logs) > MAX_LOG_ENTRIES:
69
  execution_logs.pop(0)
70
 
71
- except subprocess.TimeoutExpired:
72
- process.terminate()
73
- log_entry['error'] += "\nProcess timed out after 1 hour."
74
  except Exception as e:
75
- log_entry['error'] += f"\nUnexpected error: {str(e)}"
76
- finally:
77
- process_lock.release()
78
 
79
  def start_initial_run():
80
  threading.Thread(target=run_cli_script, daemon=True).start()
@@ -85,7 +51,7 @@ scheduler.add_job(
85
  'interval',
86
  hours=3,
87
  id='main_job',
88
- timezone=pytz.utc # Scheduler uses UTC internally
89
  )
90
  scheduler.start()
91
 
@@ -93,9 +59,10 @@ start_initial_run()
93
 
94
  @app.route('/')
95
  def home():
 
96
  job = scheduler.get_job('main_job')
97
- next_run = job.next_run_time.astimezone(pytz.timezone("Asia/Kolkata")).strftime('%Y-%m-%d %H:%M:%S IST') if job else 'N/A'
98
-
99
  return render_template_string('''
100
  <!DOCTYPE html>
101
  <html>
@@ -150,20 +117,22 @@ def home():
150
 
151
  @app.route('/logs')
152
  def logs():
153
- with log_lock:
154
- return jsonify({'logs': execution_logs[::-1]}) # Newest logs first
155
 
156
  @app.route('/force-run')
157
  def force_run():
158
- if threading.Thread(target=run_cli_script, daemon=True).start():
159
- return "Script started manually", 200
160
- return "Script is already running", 429
161
 
162
  @app.route('/run-check')
163
  def run_check():
 
164
  if not scheduler.running:
 
165
  scheduler.start()
166
  return "Scheduler is running", 200
167
 
168
  if __name__ == '__main__':
169
- app.run(host='0.0.0.0', port=7860)
 
2
  from apscheduler.schedulers.background import BackgroundScheduler
3
  import subprocess
4
  import threading
 
5
  from datetime import datetime
 
6
 
7
  app = Flask(__name__)
8
  execution_logs = []
9
+ MAX_LOG_ENTRIES = 20
 
 
10
 
11
  def run_cli_script():
12
+ """Runs cli.py and streams logs in real-time to both UI and terminal."""
13
+ timestamp = datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S UTC")
14
+ log_entry = {'time': timestamp, 'output': '', 'error': ''}
 
15
 
16
  try:
17
+ process = subprocess.Popen(
 
 
 
 
 
 
 
18
  ["python", "cli.py"],
19
  stdout=subprocess.PIPE,
20
  stderr=subprocess.PIPE,
21
+ text=True,
22
+ bufsize=1
23
+ )
24
+
25
+ # Stream logs to UI and print to terminal
26
+ for line in process.stdout:
27
+ log_entry['output'] += line
28
+ execution_logs.append({'time': timestamp, 'output': line, 'error': ''})
29
+ print(line, end="") # ✅ Print logs to terminal
30
+ if len(execution_logs) > MAX_LOG_ENTRIES:
31
+ execution_logs.pop(0)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
 
33
+ for line in process.stderr:
34
+ log_entry['error'] += line
35
+ execution_logs.append({'time': timestamp, 'output': '', 'error': line})
36
+ print(line, end="") # ✅ Print errors to terminal
37
  if len(execution_logs) > MAX_LOG_ENTRIES:
38
  execution_logs.pop(0)
39
 
 
 
 
40
  except Exception as e:
41
+ log_entry['error'] = str(e)
42
+ execution_logs.append({'time': timestamp, 'output': '', 'error': str(e)})
43
+ print(f"Error: {str(e)}") # ✅ Print error to terminal
44
 
45
  def start_initial_run():
46
  threading.Thread(target=run_cli_script, daemon=True).start()
 
51
  'interval',
52
  hours=3,
53
  id='main_job',
54
+ next_run_time=datetime.now()
55
  )
56
  scheduler.start()
57
 
 
59
 
60
  @app.route('/')
61
  def home():
62
+ """Main UI displaying logs and next run time."""
63
  job = scheduler.get_job('main_job')
64
+ next_run = job.next_run_time.strftime('%Y-%m-%d %H:%M:%S UTC') if job else 'N/A'
65
+
66
  return render_template_string('''
67
  <!DOCTYPE html>
68
  <html>
 
117
 
118
  @app.route('/logs')
119
  def logs():
120
+ """Returns logs as JSON for AJAX polling."""
121
+ return jsonify({'logs': execution_logs})
122
 
123
  @app.route('/force-run')
124
  def force_run():
125
+ """Manually trigger the script execution."""
126
+ threading.Thread(target=run_cli_script, daemon=True).start()
127
+ return "Script executed manually", 200
128
 
129
  @app.route('/run-check')
130
  def run_check():
131
+ """Check if the scheduler is still running."""
132
  if not scheduler.running:
133
+ print("Scheduler was stopped! Restarting...")
134
  scheduler.start()
135
  return "Scheduler is running", 200
136
 
137
  if __name__ == '__main__':
138
+ app.run(host='0.0.0.0', port=7860)