sammy786 commited on
Commit
881bb63
·
1 Parent(s): de3650b

flights: parallelize the 3 provider fetches per search (~3x faster; fixes slow return leg)

Browse files
Files changed (1) hide show
  1. app/flights_provider.py +14 -3
app/flights_provider.py CHANGED
@@ -24,6 +24,7 @@ Environment (never hardcoded):
24
  """
25
 
26
  import os
 
27
  from datetime import datetime, date as _date, timedelta
28
  from typing import List, Optional, Dict
29
 
@@ -250,13 +251,23 @@ def _search_once(src, dst, date, nonstop, airlines, max_price,
250
  # search_by_price_range is one-way only; use it just for one-way sweeps.
251
  if not return_date:
252
  fetchers.insert(1, lambda: _fetch_price_range(src, dst, date, nonstop, max_results, max_price))
253
- for fetch in fetchers:
 
 
 
 
 
 
 
254
  try:
255
- raw.extend(fetch())
256
  except Exception:
257
  # a single endpoint failing (rate limit, empty cache) must not sink
258
  # the whole search; we still return whatever the others gave.
259
- continue
 
 
 
260
 
261
  flights = [_normalize(r, date) for r in raw if r.get("price")]
262
  flights = _dedupe(flights)
 
24
  """
25
 
26
  import os
27
+ from concurrent.futures import ThreadPoolExecutor
28
  from datetime import datetime, date as _date, timedelta
29
  from typing import List, Optional, Dict
30
 
 
251
  # search_by_price_range is one-way only; use it just for one-way sweeps.
252
  if not return_date:
253
  fetchers.insert(1, lambda: _fetch_price_range(src, dst, date, nonstop, max_results, max_price))
254
+ # The three endpoints are INDEPENDENT Travelpayouts I/O calls. Running them
255
+ # one after another made a single search ~3x slower than the slowest call -
256
+ # and on a round trip, where the return leg is searched alongside the
257
+ # outbound, that extra latency is exactly why "the departure came but the
258
+ # return didn't load, it takes time". Fan them out on threads and gather;
259
+ # each still fails independently (a rate-limited/empty endpoint returns []),
260
+ # and ThreadPoolExecutor.map preserves order, so dedupe/rank are unchanged.
261
+ def _safe(fetch):
262
  try:
263
+ return fetch()
264
  except Exception:
265
  # a single endpoint failing (rate limit, empty cache) must not sink
266
  # the whole search; we still return whatever the others gave.
267
+ return []
268
+ with ThreadPoolExecutor(max_workers=len(fetchers)) as ex:
269
+ for part in ex.map(_safe, fetchers):
270
+ raw.extend(part)
271
 
272
  flights = [_normalize(r, date) for r in raw if r.get("price")]
273
  flights = _dedupe(flights)