Skip to content

Commit

Permalink
gbfs: correctly handle errors during provider updates (#775)
Browse files Browse the repository at this point in the history
  • Loading branch information
pablohoch authored Mar 11, 2025
1 parent 2c19105 commit d7d7cd6
Showing 1 changed file with 98 additions and 75 deletions.
173 changes: 98 additions & 75 deletions src/gbfs/update.cc
Original file line number Diff line number Diff line change
Expand Up @@ -308,93 +308,116 @@ struct gbfs_update {
gbfs_provider const* prev_provider,
std::optional<gbfs_file> discovery = std::nullopt) {
auto& file_infos = provider.file_infos_;
auto data_changed = false;

if (!discovery && needs_refresh(provider.file_infos_->urls_fi_)) {
discovery = co_await fetch_file("gbfs", pf.url_, pf.headers_, pf.dir_);
}
if (discovery) {
file_infos->urls_ = parse_discovery(discovery->json_);
file_infos->urls_fi_.expiry_ = discovery->next_refresh_;
file_infos->urls_fi_.hash_ = discovery->hash_;
}
try {
if (!discovery && needs_refresh(provider.file_infos_->urls_fi_)) {
discovery = co_await fetch_file("gbfs", pf.url_, pf.headers_, pf.dir_);
}
if (discovery) {
file_infos->urls_ = parse_discovery(discovery->json_);
file_infos->urls_fi_.expiry_ = discovery->next_refresh_;
file_infos->urls_fi_.hash_ = discovery->hash_;
}

auto const update = [&](std::string_view const name, file_info& fi,
auto const& fn,
bool const force = false) -> awaitable<bool> {
if (force || (file_infos->urls_.contains(name) && needs_refresh(fi))) {
auto file = co_await fetch_file(name, file_infos->urls_.at(name),
pf.headers_, pf.dir_);
auto const hash_changed = file.hash_ != fi.hash_;
auto j_root = file.json_.as_object();
fi.expiry_ = file.next_refresh_;
fi.hash_ = file.hash_;
fn(provider, file.json_);
co_return hash_changed;
auto const update = [&](std::string_view const name, file_info& fi,
auto const& fn,
bool const force = false) -> awaitable<bool> {
if (force || (file_infos->urls_.contains(name) && needs_refresh(fi))) {
auto file = co_await fetch_file(name, file_infos->urls_.at(name),
pf.headers_, pf.dir_);
auto const hash_changed = file.hash_ != fi.hash_;
auto j_root = file.json_.as_object();
fi.expiry_ = file.next_refresh_;
fi.hash_ = file.hash_;
fn(provider, file.json_);
co_return hash_changed;
}
co_return false;
};

auto const sys_info_updated = co_await update(
"system_information", file_infos->system_information_fi_,
load_system_information);
if (!sys_info_updated && prev_provider != nullptr) {
provider.sys_info_ = prev_provider->sys_info_;
}
co_return false;
};

auto const sys_info_updated = co_await update(
"system_information", file_infos->system_information_fi_,
load_system_information);
if (!sys_info_updated && prev_provider != nullptr) {
provider.sys_info_ = prev_provider->sys_info_;
}
auto const vehicle_types_updated = co_await update(
"vehicle_types", file_infos->vehicle_types_fi_, load_vehicle_types);
if (!vehicle_types_updated && prev_provider != nullptr) {
provider.vehicle_types_ = prev_provider->vehicle_types_;
provider.vehicle_types_map_ = prev_provider->vehicle_types_map_;
provider.temp_vehicle_types_ = prev_provider->temp_vehicle_types_;
}

auto const vehicle_types_updated = co_await update(
"vehicle_types", file_infos->vehicle_types_fi_, load_vehicle_types);
if (!vehicle_types_updated && prev_provider != nullptr) {
provider.vehicle_types_ = prev_provider->vehicle_types_;
provider.vehicle_types_map_ = prev_provider->vehicle_types_map_;
provider.temp_vehicle_types_ = prev_provider->temp_vehicle_types_;
}
auto const stations_updated = co_await update(
"station_information", file_infos->station_information_fi_,
load_station_information);
if (!stations_updated && prev_provider != nullptr) {
provider.stations_ = prev_provider->stations_;
}

auto const stations_updated = co_await update(
"station_information", file_infos->station_information_fi_,
load_station_information);
if (!stations_updated && prev_provider != nullptr) {
provider.stations_ = prev_provider->stations_;
}
auto const station_status_updated =
co_await update("station_status", file_infos->station_status_fi_,
load_station_status, stations_updated);

auto const vehicle_status_updated =
co_await update("vehicle_status", file_infos->vehicle_status_fi_,
load_vehicle_status) // 3.x
|| co_await update("free_bike_status", file_infos->vehicle_status_fi_,
load_vehicle_status); // 1.x / 2.x
if (!vehicle_status_updated && prev_provider != nullptr) {
provider.vehicle_status_ = prev_provider->vehicle_status_;
}

auto const station_status_updated =
co_await update("station_status", file_infos->station_status_fi_,
load_station_status, stations_updated);

auto const vehicle_status_updated =
co_await update("vehicle_status", file_infos->vehicle_status_fi_,
load_vehicle_status) // 3.x
|| co_await update("free_bike_status", file_infos->vehicle_status_fi_,
load_vehicle_status); // 1.x / 2.x
if (!vehicle_status_updated && prev_provider != nullptr) {
provider.vehicle_status_ = prev_provider->vehicle_status_;
}
auto const geofencing_updated =
co_await update("geofencing_zones", file_infos->geofencing_zones_fi_,
load_geofencing_zones);
if (!geofencing_updated && prev_provider != nullptr) {
provider.geofencing_zones_ = prev_provider->geofencing_zones_;
}

auto const geofencing_updated =
co_await update("geofencing_zones", file_infos->geofencing_zones_fi_,
load_geofencing_zones);
if (!geofencing_updated && prev_provider != nullptr) {
provider.geofencing_zones_ = prev_provider->geofencing_zones_;
}
if (prev_provider != nullptr) {
provider.has_vehicles_to_rent_ = prev_provider->has_vehicles_to_rent_;
}

if (prev_provider != nullptr) {
provider.has_vehicles_to_rent_ = prev_provider->has_vehicles_to_rent_;
}
data_changed = vehicle_types_updated || stations_updated ||
station_status_updated || vehicle_status_updated ||
geofencing_updated;
} catch (std::exception const& ex) {
std::cerr << "[GBFS] error processing feed " << pf.id_ << " (" << pf.url_
<< "): " << ex.what() << "\n";

auto const data_changed = vehicle_types_updated || stations_updated ||
station_status_updated ||
vehicle_status_updated || geofencing_updated;
// keep previous data
if (prev_provider != nullptr) {
provider.sys_info_ = prev_provider->sys_info_;
provider.vehicle_types_ = prev_provider->vehicle_types_;
provider.vehicle_types_map_ = prev_provider->vehicle_types_map_;
provider.temp_vehicle_types_ = prev_provider->temp_vehicle_types_;
provider.stations_ = prev_provider->stations_;
provider.vehicle_status_ = prev_provider->vehicle_status_;
provider.geofencing_zones_ = prev_provider->geofencing_zones_;
provider.has_vehicles_to_rent_ = prev_provider->has_vehicles_to_rent_;
}
}

if (data_changed) {
partition_provider(provider);
provider.has_vehicles_to_rent_ = utl::any_of(
provider.products_,
[](auto const& prod) { return prod.has_vehicles_to_rent_; });

update_rtree(provider, prev_provider);

d_->cache_.try_add_or_update(provider.idx_, [&]() {
return compute_provider_routing_data(w_, l_, provider);
});
try {
partition_provider(provider);
provider.has_vehicles_to_rent_ = utl::any_of(
provider.products_,
[](auto const& prod) { return prod.has_vehicles_to_rent_; });

update_rtree(provider, prev_provider);

d_->cache_.try_add_or_update(provider.idx_, [&]() {
return compute_provider_routing_data(w_, l_, provider);
});
} catch (std::exception const& ex) {
std::cerr << "[GBFS] error updating provider " << pf.id_ << ": "
<< ex.what() << "\n";
}
} else if (prev_provider != nullptr) {
// data not changed, copy previously computed products
provider.products_ = prev_provider->products_;
Expand Down

0 comments on commit d7d7cd6

Please sign in to comment.