Cache walk-on NR fares by day of week for instant display
Store GWR walk-on fares keyed by timetable period + weekday
(weekday_gwr_fares_{direction}_{crs}_{period}_{day}), mirroring
the existing NR timetable weekday cache strategy.
On page load the server embeds any cached weekday fares in the page
as WALKON_CACHED_FARES so JS can populate prices immediately without
waiting for the GWR API. The live API call still runs afterwards to
verify and update any changed fares; the spinner label changes to
"Verifying fares" when cached prices are already shown.
The weekday cache is written whenever exact-date fares are fetched
from GWR, keeping it fresh, and populated lazily from the exact-date
cache on first access.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
1bc7631863
commit
5f0d2c71b1
2 changed files with 28 additions and 0 deletions
18
app.py
18
app.py
|
|
@ -129,6 +129,13 @@ def _nr_weekday_cache_key(direction: str, station_crs: str, section_date: str) -
|
|||
)
|
||||
|
||||
|
||||
def _walkon_weekday_cache_key(direction: str, station_crs: str, section_date: str) -> str:
|
||||
return (
|
||||
f"weekday_gwr_fares_{direction}_{station_crs}_"
|
||||
f"{_nr_timetable_period_key(section_date)}_{_weekday_for(section_date)}"
|
||||
)
|
||||
|
||||
|
||||
def _eurostar_exact_cache_key(direction: str, section_date: str, destination: str) -> str:
|
||||
return f"eurostar_{direction}_{section_date}_{destination}"
|
||||
|
||||
|
|
@ -517,6 +524,9 @@ def _results(station_crs, slug, travel_date, journey_type, return_date):
|
|||
fare_direction = "to_paddington" if direction == "outbound" else "from_paddington"
|
||||
gwr_fares = {}
|
||||
cached_advance = get_cached(advance_cache_key, ttl=24 * 3600)
|
||||
walkon_weekday_key = _walkon_weekday_cache_key(rtt_direction, station_crs, section_date)
|
||||
exact_walkon = get_cached(gwr_cache_key, ttl=30 * 24 * 3600)
|
||||
cached_walkon = exact_walkon if exact_walkon is not None else get_cached(walkon_weekday_key)
|
||||
|
||||
if direction == "outbound":
|
||||
trips = combine_trips(
|
||||
|
|
@ -603,6 +613,7 @@ def _results(station_crs, slug, travel_date, journey_type, return_date):
|
|||
"max_connection": section_max_connection,
|
||||
"provisional_timetable": nr_provisional or es_provisional,
|
||||
"advance_fares": cached_advance,
|
||||
"cached_walkon_fares": cached_walkon,
|
||||
"walkon_api_url": url_for(
|
||||
"api_walkon_fares",
|
||||
station_crs=station_crs,
|
||||
|
|
@ -755,11 +766,13 @@ def _results(station_crs, slug, travel_date, journey_type, return_date):
|
|||
|
||||
trip_fares = {}
|
||||
advance_fares = {}
|
||||
walkon_cached_fares = {}
|
||||
walkon_api_urls = {}
|
||||
advance_api_urls = {}
|
||||
advance_stream_urls = {}
|
||||
for section in sections:
|
||||
advance_fares[section["id"]] = section["advance_fares"]
|
||||
walkon_cached_fares[section["id"]] = section.get("cached_walkon_fares")
|
||||
walkon_api_urls[section["id"]] = section["walkon_api_url"]
|
||||
advance_api_urls[section["id"]] = section["advance_api_url"]
|
||||
advance_stream_urls[section["id"]] = section["advance_stream_url"]
|
||||
|
|
@ -860,6 +873,7 @@ def _results(station_crs, slug, travel_date, journey_type, return_date):
|
|||
section_directions_json=json.dumps(section_directions),
|
||||
trip_fares_json=json.dumps(trip_fares),
|
||||
advance_fares_json=json.dumps(advance_fares),
|
||||
walkon_cached_fares_json=json.dumps(walkon_cached_fares),
|
||||
walkon_api_urls_json=json.dumps(walkon_api_urls),
|
||||
advance_api_urls_json=json.dumps(advance_api_urls),
|
||||
advance_stream_urls_json=json.dumps(advance_stream_urls),
|
||||
|
|
@ -918,8 +932,11 @@ def api_walkon_fares(station_crs, travel_date):
|
|||
if direction not in {"to_paddington", "from_paddington"}:
|
||||
direction = "to_paddington"
|
||||
cache_key = f"gwr_fares_{direction}_{station_crs}_{travel_date}"
|
||||
weekday_key = _walkon_weekday_cache_key(direction, station_crs, travel_date)
|
||||
cached = get_cached(cache_key, ttl=30 * 24 * 3600)
|
||||
if cached is not None:
|
||||
if get_cached(weekday_key) is None:
|
||||
set_cached(weekday_key, cached)
|
||||
return jsonify(cached)
|
||||
try:
|
||||
fares = (
|
||||
|
|
@ -928,6 +945,7 @@ def api_walkon_fares(station_crs, travel_date):
|
|||
else gwr_fares_scraper.fetch(station_crs, travel_date, direction=direction)
|
||||
)
|
||||
set_cached(cache_key, fares)
|
||||
set_cached(weekday_key, fares)
|
||||
return jsonify(fares)
|
||||
except Exception as e:
|
||||
return jsonify({"error": str(e)}), 500
|
||||
|
|
|
|||
|
|
@ -142,6 +142,7 @@
|
|||
const DEFAULT_MIN_CONN_IN = {{ default_inbound_min_connection }};
|
||||
let TRIP_FARES = {{ trip_fares_json | safe }};
|
||||
let ADVANCE_FARES = {{ advance_fares_json | safe }};
|
||||
const WALKON_CACHED_FARES = {{ walkon_cached_fares_json | safe }};
|
||||
let WALKON_API_URLS = {{ walkon_api_urls_json | safe }};
|
||||
let ADVANCE_API_URLS = {{ advance_api_urls_json | safe }};
|
||||
let ADVANCE_STREAM_URLS = {{ advance_stream_urls_json | safe }};
|
||||
|
|
@ -566,8 +567,17 @@
|
|||
return c === 'advance_std' || c === 'advance_1st';
|
||||
});
|
||||
if (needsAdvance) loadMissingAdvanceFares();
|
||||
/* Pre-populate walk-on fares from weekday cache so prices show immediately */
|
||||
var hasPreloaded = false;
|
||||
for (var sid in WALKON_CACHED_FARES) {
|
||||
if (WALKON_CACHED_FARES[sid]) { mergeWalkonFares(sid, WALKON_CACHED_FARES[sid]); hasPreloaded = true; }
|
||||
}
|
||||
updateDisplay();
|
||||
updateRowHighlights();
|
||||
if (hasPreloaded) {
|
||||
var loadingEl = document.getElementById('walkon-loading');
|
||||
if (loadingEl) loadingEl.innerHTML = '<span class="spinner spinner-inline" aria-hidden="true"></span>Verifying fares';
|
||||
}
|
||||
loadWalkonFares();
|
||||
startTimetableRefresh();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue