-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathapp.py
More file actions
94 lines (78 loc) · 3.54 KB
/
app.py
File metadata and controls
94 lines (78 loc) · 3.54 KB
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
import time
import os
from datetime import datetime, timedelta, timezone
import traceback
from flask import Flask
from flask_cors import CORS
import threading
import logging
from blueprints.edst_bp import edst_blueprint
from blueprints.navdata_bp import navdata_blueprint
from blueprints.prefroute_bp import prefroute_blueprint
from blueprints.weather_bp import weather_blueprint
from blueprints.route_analysis_bp import route_analysis_blueprint
import mongo_client
from libs.wind_lib import get_rap_grib2_stream, interpolate_uv_temp_at_flight_levels, get_latest_rap_forecast
from libs.weather_data_lock import WindGridState, weather_data, data_lock
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
PREFIX = '/api'
def create_app():
app = Flask(__name__)
CORS(app)
app.config['CORS_HEADERS'] = 'Content-Type'
register_extensions(app)
return app
def register_extensions(app):
app.register_blueprint(prefroute_blueprint, url_prefix=f'{PREFIX}/prefroute')
app.register_blueprint(navdata_blueprint, url_prefix=f'{PREFIX}/navdata')
app.register_blueprint(weather_blueprint, url_prefix=f'{PREFIX}/weather')
app.register_blueprint(edst_blueprint, url_prefix=f'{PREFIX}/edst')
app.register_blueprint(route_analysis_blueprint, url_prefix=f'{PREFIX}/route')
@app.before_request
def _get_mongo_clients():
mongo_client.get_reader_mongo_client()
@app.after_request
def _close_mongo_clients(response):
mongo_client.close_reader_mongo_client()
return response
def run_updater():
"""Run once at startup and then every hour at HH:05 UTC."""
while True:
try:
# Always run once immediately at startup
date_info = get_latest_rap_forecast()
grib_stream = get_rap_grib2_stream(date_info.date_str, date_info.cycle_hour, date_info.forecast_hour)
logging.info(f"Downloaded GRIB2 stream for {date_info.date_str} {date_info.cycle_hour}z f{date_info.forecast_hour}")
if grib_stream is None:
logging.error("[Updater] Error, failed to download GRIB2 stream")
time.sleep(300) # retry in 5 min if failed
continue
interpolate_uv_temp_at_flight_levels(grib_stream)
with data_lock:
weather_data.wx_state = WindGridState(
process_date=date_info.date_str,
process_cycle=date_info.cycle_hour,
forecast_hour=date_info.forecast_hour,
processed_at_utc=datetime.now(timezone.utc).isoformat()
)
logging.info(f"[Updater] Weather data updated {date_info.date_str} {date_info.cycle_hour}z f{date_info.forecast_hour}")
# schedule next run at the next HH:05 UTC
now = datetime.now(timezone.utc)
next_run = now.replace(minute=5, second=0, microsecond=0)
if now >= next_run:
next_run = next_run + timedelta(hours=1)
sleep_seconds = (next_run - now).total_seconds()
logging.info(f"[Updater] Next run scheduled at {next_run.isoformat()} (in {int(sleep_seconds)}s)")
time.sleep(sleep_seconds)
except Exception as e:
logging.error(f"Updater error: {e}")
traceback.print_exc()
time.sleep(300) # retry in 5 min if failed
if __name__ == '__main__':
updater_thread = threading.Thread(target=run_updater, daemon=True)
updater_thread.start()
app = create_app()
app.run(use_reloader=True)