Added processing of failures in local ads campaigns downloading

This commit is contained in:
r.kuznetsov 2017-05-10 14:16:37 +03:00
parent 075d39e705
commit bf54144093
2 changed files with 101 additions and 34 deletions

View file

@ -37,6 +37,9 @@ std::string const kCampaignPageUrl = LOCAL_ADS_COMPANY_PAGE_URL;
std::string const kCampaignFile = "local_ads_campaigns.dat";
std::string const kLocalAdsSymbolsFile = "local_ads_symbols.txt";
auto constexpr kWWanUpdateTimeout = std::chrono::hours(12);
uint8_t constexpr kRequestMinZoomLevel = 12;
auto constexpr kFailedDownloadingTimeout = std::chrono::seconds(2);
auto constexpr kMaxDownloadingAttempts = 5;
void SerializeCampaign(FileWriter & writer, std::string const & countryName,
LocalAdsManager::Timestamp const & ts,
@ -76,20 +79,6 @@ std::string MakeCampaignDownloadingURL(MwmSet::MwmId const & mwmId)
return ss.str();
}
std::vector<uint8_t> DownloadCampaign(MwmSet::MwmId const & mwmId)
{
std::string const url = MakeCampaignDownloadingURL(mwmId);
if (url.empty())
return {};
platform::HttpClient request(url);
if (!request.RunHttpRequest() || request.ErrorCode() != 200)
return {};
string const & response = request.ServerResponse();
return std::vector<uint8_t>(response.cbegin(), response.cend());
}
df::CustomSymbols ParseCampaign(std::vector<uint8_t> const & rawData, MwmSet::MwmId const & mwmId,
LocalAdsManager::Timestamp timestamp)
{
@ -225,7 +214,7 @@ void LocalAdsManager::UpdateViewport(ScreenBase const & screen)
{
auto connectionStatus = GetPlatform().ConnectionStatus();
if (kServerUrl.empty() || connectionStatus == Platform::EConnectionType::CONNECTION_NONE ||
df::GetZoomLevel(screen.GetScale()) <= scales::GetUpperWorldScale())
df::GetZoomLevel(screen.GetScale()) < kRequestMinZoomLevel)
{
return;
}
@ -246,6 +235,18 @@ void LocalAdsManager::UpdateViewport(ScreenBase const & screen)
auto info = mwm.GetInfo();
if (!info)
continue;
// Skip downloading request if maximum attempts count has reached or
// we are waiting for new attempt.
auto const failedDownloadsIt = m_failedDownloads.find(mwm);
if (failedDownloadsIt != m_failedDownloads.cend() &&
(failedDownloadsIt->second.m_attemptsCount >= kMaxDownloadingAttempts ||
Now() <= failedDownloadsIt->second.m_lastDownloading +
failedDownloadsIt->second.m_currentTimeout))
{
continue;
}
std::string const & mwmName = info->GetCountryName();
auto campaignIt = m_campaigns.find(mwmName);
if (campaignIt == m_campaigns.end())
@ -276,6 +277,51 @@ void LocalAdsManager::UpdateViewport(ScreenBase const & screen)
}
}
bool LocalAdsManager::DownloadCampaign(MwmSet::MwmId const & mwmId, std::vector<uint8_t> & bytes)
{
bytes.clear();
std::string const url = MakeCampaignDownloadingURL(mwmId);
if (url.empty())
return true;
// Skip already downloaded campaigns. We do not lock whole method because RunHttpRequest
// is a synchronous method and may take a lot of time. The case in which countryName will
// be added to m_campaigns between locks is neglected.
{
std::lock_guard<std::mutex> lock(m_mutex);
auto const & countryName = mwmId.GetInfo()->GetCountryName();
if (m_campaigns.find(countryName) != m_campaigns.cend())
return false;
}
platform::HttpClient request(url);
bool const success = request.RunHttpRequest() && request.ErrorCode() == 200;
std::lock_guard<std::mutex> lock(m_mutex);
if (!success)
{
auto const it = m_failedDownloads.find(mwmId);
if (it == m_failedDownloads.cend())
{
m_failedDownloads.insert(std::make_pair(
mwmId, BackoffStats(Now(), kFailedDownloadingTimeout, 1 /* m_attemptsCount */)));
}
else
{
// Here we increase timeout as power 2 function.
it->second.m_currentTimeout = std::chrono::seconds(it->second.m_currentTimeout.count() << 1);
it->second.m_attemptsCount++;
}
return false;
}
m_failedDownloads.erase(mwmId);
auto const & response = request.ServerResponse();
bytes.assign(response.cbegin(), response.cend());
return true;
}
void LocalAdsManager::ThreadRoutine()
{
local_ads::IconsInfo::Instance().SetSourceFile(kLocalAdsSymbolsFile);
@ -299,25 +345,28 @@ void LocalAdsManager::ThreadRoutine()
{
// Download campaign data from server.
CampaignInfo info;
info.m_data = DownloadCampaign(mwm.first);
if (info.m_data.empty())
if (!DownloadCampaign(mwm.first, info.m_data))
continue;
info.m_created = Now();
// Parse data and send symbols to rendering.
auto symbols = ParseCampaign(std::move(info.m_data), mwm.first, info.m_created);
if (symbols.empty())
// Parse data and send symbols to rendering (or delete from rendering).
if (!info.m_data.empty())
{
std::lock_guard<std::mutex> lock(m_mutex);
m_campaigns.erase(countryName);
m_info.erase(countryName);
DeleteSymbolsFromRendering(mwm.first);
auto symbols = ParseCampaign(std::move(info.m_data), mwm.first, info.m_created);
if (symbols.empty())
{
DeleteSymbolsFromRendering(mwm.first);
}
else
{
UpdateFeaturesCache(symbols);
SendSymbolsToRendering(std::move(symbols));
}
}
else
{
UpdateFeaturesCache(symbols);
SendSymbolsToRendering(std::move(symbols));
DeleteSymbolsFromRendering(mwm.first);
}
info.m_created = Now();
// Update run-time data.
{

View file

@ -82,6 +82,8 @@ private:
void FillSupportedTypes();
bool DownloadCampaign(MwmSet::MwmId const & mwmId, std::vector<uint8_t> & bytes);
GetMwmsByRectFn m_getMwmsByRectFn;
GetMwmIdByName m_getMwmIdByNameFn;
@ -98,16 +100,32 @@ private:
df::CustomSymbols m_symbolsCache;
std::mutex m_symbolsCacheMutex;
std::set<FeatureID> m_featuresCache;
mutable std::mutex m_featuresCacheMutex;
ftypes::HashSetMatcher<uint32_t> m_supportedTypes;
struct BackoffStats
{
BackoffStats() = default;
BackoffStats(Timestamp lastDownloading, std::chrono::seconds currentTimeout,
uint8_t attemptsCount)
: m_lastDownloading(lastDownloading)
, m_currentTimeout(currentTimeout)
, m_attemptsCount(attemptsCount)
{}
Timestamp m_lastDownloading = {};
std::chrono::seconds m_currentTimeout = std::chrono::seconds(0);
uint8_t m_attemptsCount = 0;
};
std::map<MwmSet::MwmId, BackoffStats> m_failedDownloads;
local_ads::Statistics m_statistics;
bool m_isRunning = false;
std::condition_variable m_condition;
std::set<Request> m_requestedCampaigns;
std::mutex m_mutex;
threads::SimpleThread m_thread;
local_ads::Statistics m_statistics;
std::set<FeatureID> m_featuresCache;
mutable std::mutex m_featuresCacheMutex;
ftypes::HashSetMatcher<uint32_t> m_supportedTypes;
};