Files
UnrealEngineUWP/Engine/Source/Runtime/Online/HTTP/Private/HttpRetrySystem.cpp
Andrew Grant 13a9fa2498 Copying //UE4/Orion-Staging to //UE4/Main (Source: //Orion/Dev-General @ 2845681)
#lockdown Nick.Penwarden

==========================
MAJOR FEATURES + CHANGES
==========================

Change 2845644 on 2016/01/27 by Martin.Wilson

	Clear marker sync flag after creating tick record, add more information to checks incase issue occurs again

	#Jira OR-13469
	#rb Thomas.Sarkanen
	#tests in editor tests, bot match.

Change 2845613 on 2016/01/27 by John.Pollard

	Latest network profiler binaries

	#rb none
	#tests run profiler

Change 2845595 on 2016/01/27 by Mieszko.Zielinski

	Fixed pathfollowing's block detection using wrong distance when testing for blockage #UE4

	#rb Lukasz.Furman
	#test golden path

Change 2845593 on 2016/01/27 by Jeff.Farris

	Added support for setting and choosing filmbacks and lenses for cinematic cameras.
	- New CineCameraComponent and CineCameraActor classes
	- can define filmback and lens presets via ini file
	- details customizations for filmback and lens selection
	- added prototype set of filmbacks and lenses (primes and zooms)
	- Camera details customization now gracefully handles when CameraSettings category is hidden
	- example sequencer usage is content/developers/jeff.farris/CineCams/CineCamTestMap

	#rb none
	#tests editor

Change 2845585 on 2016/01/27 by Marcus.Wassmer

	Don't fool with connected state if we're early outing from the OS intercepting controller events.  This fixes some missing delegates.
	Fixes cert bug about controller disconnect screen staying up permanently
	#rb Cody.Haskell
	#test Turning off controller, turning on again.
	#lockdown Andrew.Grant

Change 2845528 on 2016/01/27 by Max.Chen

	Sequencer: Fix new spawnables not immediately getting an object binding. This was resulted in a missing +Track->Animation when first creating a spawnable and duplicate transform keys.

	#jira UE-26084
	#tests Add spawnable, +Track->Animation exists
	#rb none

Change 2845483 on 2016/01/27 by Andrew.Rodham

	Sequencer: Fixed MaximizedViewport not getting cleared/restored correctly
	#jria UE-26016
	#rb Max.Chen
	#tests Tested the viewports

Change 2845421 on 2016/01/27 by Max.Preussner

	Sequencer: Implemented go-to feature

	#RB max.chen
	#TESTS Editor

Change 2845407 on 2016/01/27 by Max.Preussner

	Sequencer: Moved SetViewRange() into ISequencer and made it public

	#RB max.chen
	#TESTS none

Change 2845404 on 2016/01/27 by Andrew.Rodham

	Sequencer: Fixed cinematic viewport not updating when dragging transport range
	#jira UE-26003
	#rb Max.Chen
	#tests Scrubbed the timeline

Change 2845396 on 2016/01/27 by David.Nikdel

	#OSS #Purchase #Store #PS4
	- Minor log cleanup
	#RB: none
	#TESTS: compiles

Change 2845375 on 2016/01/27 by Max.Chen

	Sequencer: Implement cinematic shot track thumbnails.

	#jira UE-25125
	#tests Rebuild the trailer with the cinematic shot track
	#rb none

Change 2845359 on 2016/01/27 by Marcus.Wassmer

	Downgrade some checks to ensures.
	#rb none
	#test ps4

Change 2845347 on 2016/01/27 by Nicholas.Davies

	Remove unused EditorStyle dependency from Social. It is not being used, and causes issues for the engine team.
	#RB Antony.Carter
	#TESTS n/a
	#codereview Robert.Manuszewski

Change 2845227 on 2016/01/27 by Robert.Manuszewski

	Adding flags to create callstack map files when building Arxan protection

	#rb none
	#tests Built arxan exe

Change 2844871 on 2016/01/26 by Andrew.Grant

	Prevent enums from being regenerated while cooking (prevents false-positive warning about FText's being regenerated)
	#rb none
	#tests ran editor

[CL 2847722 by Andrew Grant in Main branch]
2016-01-28 16:03:26 -05:00

386 lines
13 KiB
C++

// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
#include "HttpPrivatePCH.h"
#include "HttpRetrySystem.h"
FHttpRetrySystem::FRequest::FRequest(
const TSharedRef<IHttpRequest>& HttpRequest,
const FHttpRetrySystem::FRetryLimitCountSetting& InRetryLimitCountOverride,
const FHttpRetrySystem::FRetryTimeoutRelativeSecondsSetting& InRetryTimeoutRelativeSecondsOverride,
const FHttpRetrySystem::FRetryResponseCodes& InRetryResponseCodes
)
: FHttpRequestAdapterBase(HttpRequest)
, Status(FHttpRetrySystem::FRequest::EStatus::NotStarted)
, RetryLimitCountOverride(InRetryLimitCountOverride)
, RetryTimeoutRelativeSecondsOverride(InRetryTimeoutRelativeSecondsOverride)
, RetryResponseCodes(InRetryResponseCodes)
{
// if the InRetryTimeoutRelativeSecondsOverride override is being used the value cannot be negative
check(!(InRetryTimeoutRelativeSecondsOverride.bUseValue) || (InRetryTimeoutRelativeSecondsOverride.Value >= 0.0));
}
FHttpRetrySystem::FManager::FManager(const FRetryLimitCountSetting& InRetryLimitCountDefault, const FRetryTimeoutRelativeSecondsSetting& InRetryTimeoutRelativeSecondsDefault)
: RandomFailureRate(FRandomFailureRateSetting::Unused())
, RetryLimitCountDefault(InRetryLimitCountDefault)
, RetryTimeoutRelativeSecondsDefault(InRetryTimeoutRelativeSecondsDefault)
{}
bool FHttpRetrySystem::FManager::ShouldRetry(const FHttpRetryRequestEntry& HttpRetryRequestEntry)
{
bool bResult = false;
FHttpResponsePtr Response = HttpRetryRequestEntry.HttpRequest->GetResponse();
// invalid response means connection or network error but we need to know which one
if (!Response.IsValid())
{
// ONLY retry bad responses if they are connection errors (NOT protocol errors or unknown) otherwise request may be sent (and processed!) twice
EHttpRequestStatus::Type Status = HttpRetryRequestEntry.HttpRequest->GetRequestStatus();
if (Status == EHttpRequestStatus::Failed_ConnectionError)
{
bResult = true;
}
else if (Status == EHttpRequestStatus::Failed)
{
// we will also allow retry for GET and HEAD requests even if they may duplicate on the server
FString Verb = HttpRetryRequestEntry.HttpRequest->GetVerb();
if (Verb == TEXT("GET") || Verb == TEXT("HEAD"))
{
bResult = true;
}
}
}
else
{
// this may be a successful response with one of the explicitly listed response codes we want to retry on
if (HttpRetryRequestEntry.HttpRequest->RetryResponseCodes.Contains(Response->GetResponseCode()))
{
bResult = true;
}
}
return bResult;
}
bool FHttpRetrySystem::FManager::CanRetry(const FHttpRetryRequestEntry& HttpRetryRequestEntry)
{
bool bResult = false;
bool bShouldTestCurrentRetryCount = false;
double RetryLimitCount = 0;
if (HttpRetryRequestEntry.HttpRequest->RetryLimitCountOverride.bUseValue)
{
bShouldTestCurrentRetryCount = true;
RetryLimitCount = HttpRetryRequestEntry.HttpRequest->RetryLimitCountOverride.Value;
}
else if (RetryLimitCountDefault.bUseValue)
{
bShouldTestCurrentRetryCount = true;
RetryLimitCount = RetryLimitCountDefault.Value;
}
if (bShouldTestCurrentRetryCount)
{
if (HttpRetryRequestEntry.CurrentRetryCount < RetryLimitCount)
{
bResult = true;
}
}
return bResult;
}
bool FHttpRetrySystem::FManager::HasTimedOut(const FHttpRetryRequestEntry& HttpRetryRequestEntry, const double NowAbsoluteSeconds)
{
bool bResult = false;
bool bShouldTestRetryTimeout = false;
double RetryTimeoutAbsoluteSeconds = HttpRetryRequestEntry.RequestStartTimeAbsoluteSeconds;
if (HttpRetryRequestEntry.HttpRequest->RetryTimeoutRelativeSecondsOverride.bUseValue)
{
bShouldTestRetryTimeout = true;
RetryTimeoutAbsoluteSeconds += HttpRetryRequestEntry.HttpRequest->RetryTimeoutRelativeSecondsOverride.Value;
}
else if (RetryTimeoutRelativeSecondsDefault.bUseValue)
{
bShouldTestRetryTimeout = true;
RetryTimeoutAbsoluteSeconds += RetryTimeoutRelativeSecondsDefault.Value;
}
if (bShouldTestRetryTimeout)
{
if (NowAbsoluteSeconds >= RetryTimeoutAbsoluteSeconds)
{
bResult = true;
}
}
return bResult;
}
float FHttpRetrySystem::FManager::GetLockoutPeriodSeconds(const FHttpRetryRequestEntry& HttpRetryRequestEntry)
{
float lockoutTime = 0.0f;
if(HttpRetryRequestEntry.CurrentRetryCount >= 1)
{
lockoutTime = 5.0f + 5.0f * ((HttpRetryRequestEntry.CurrentRetryCount - 1) >> 1);
lockoutTime = lockoutTime > 30.0f ? 30.0f : lockoutTime;
}
return lockoutTime;
}
static FRandomStream temp(4435261);
bool FHttpRetrySystem::FManager::Update(uint32* FileCount, uint32* FailingCount, uint32* FailedCount, uint32* CompletedCount)
{
bool bIsGreen = true;
if (FileCount != nullptr)
{
*FileCount = RequestList.Num();
}
const double NowAbsoluteSeconds = FPlatformTime::Seconds();
// Basic algorithm
// for each managed item
// if the item hasn't timed out
// if the item's retry state is NotStarted
// if the item's request's state is not NotStarted
// move the item's retry state to Processing
// endif
// endif
// if the item's retry state is Processing
// if the item's request's state is Failed
// flag return code to false
// if the item can be retried
// increment FailingCount if applicable
// retry the item's request
// increment the item's retry count
// else
// increment FailedCount if applicable
// set the item's retry state to FailedRetry
// endif
// else if the item's request's state is Succeeded
// endif
// endif
// else
// flag return code to false
// set the item's retry state to FailedTimeout
// increment FailedCount if applicable
// endif
// if the item's retry state is FailedRetry
// do stuff
// endif
// if the item's retry state is FailedTimeout
// do stuff
// endif
// if the item's retry state is Succeeded
// do stuff
// endif
// endfor
int32 index = 0;
while (index < RequestList.Num())
{
FHttpRetryRequestEntry& HttpRetryRequestEntry = RequestList[index];
TSharedRef<FHttpRetrySystem::FRequest>& HttpRetryRequest = HttpRetryRequestEntry.HttpRequest;
EHttpRequestStatus::Type RequestStatus = HttpRetryRequest->HttpRequest->GetStatus();
if (!HasTimedOut(HttpRetryRequestEntry, NowAbsoluteSeconds))
{
if (HttpRetryRequest->Status == FHttpRetrySystem::FRequest::EStatus::NotStarted)
{
if (RequestStatus != EHttpRequestStatus::NotStarted)
{
HttpRetryRequest->Status = FHttpRetrySystem::FRequest::EStatus::Processing;
}
}
if (HttpRetryRequest->Status == FHttpRetrySystem::FRequest::EStatus::Processing)
{
bool forceFail = false;
// Code to simulate request failure
if (RequestStatus == EHttpRequestStatus::Succeeded && RandomFailureRate.bUseValue)
{
float random = temp.GetFraction();
if (random < RandomFailureRate.Value)
{
forceFail = true;
}
}
// Save these for failure case retry checks if we hit a completion state
bool bShouldRetry = false;
bool bCanRetry = false;
if (RequestStatus == EHttpRequestStatus::Failed || RequestStatus == EHttpRequestStatus::Failed_ConnectionError || RequestStatus == EHttpRequestStatus::Succeeded)
{
bShouldRetry = ShouldRetry(HttpRetryRequestEntry);
bCanRetry = CanRetry(HttpRetryRequestEntry);
}
if (RequestStatus == EHttpRequestStatus::Failed || RequestStatus == EHttpRequestStatus::Failed_ConnectionError || forceFail || (bShouldRetry && bCanRetry))
{
bIsGreen = false;
if(HttpRetryRequestEntry.bShouldCancel == false)
{
if (forceFail || (bShouldRetry && bCanRetry))
{
float lockoutPeriod = GetLockoutPeriodSeconds(HttpRetryRequestEntry);
if(lockoutPeriod > 0.0f)
{
UE_LOG(LogHttp, Warning, TEXT("Lockout of %fs on %s"), lockoutPeriod, *(HttpRetryRequest->GetURL()));
}
HttpRetryRequestEntry.LockoutEndTimeAbsoluteSeconds = NowAbsoluteSeconds + lockoutPeriod;
HttpRetryRequest->Status = FHttpRetrySystem::FRequest::EStatus::ProcessingLockout;
}
else
{
UE_LOG(LogHttp, Warning, TEXT("Retry exhausted on %s"), *(HttpRetryRequest->GetURL()));
if (FailedCount != nullptr)
{
++(*FailedCount);
}
HttpRetryRequest->Status = FHttpRetrySystem::FRequest::EStatus::FailedRetry;
}
}
else
{
UE_LOG(LogHttp, Warning, TEXT("Request cancelled on %s"), *(HttpRetryRequest->GetURL()));
HttpRetryRequest->Status = FHttpRetrySystem::FRequest::EStatus::Cancelled;
}
}
else if (RequestStatus == EHttpRequestStatus::Succeeded)
{
if (HttpRetryRequestEntry.CurrentRetryCount > 0)
{
UE_LOG(LogHttp, Warning, TEXT("Success on %s"), *(HttpRetryRequest->GetURL()));
}
if (CompletedCount != nullptr)
{
++(*CompletedCount);
}
HttpRetryRequest->Status = FHttpRetrySystem::FRequest::EStatus::Succeeded;
}
}
if (HttpRetryRequest->Status == FHttpRetrySystem::FRequest::EStatus::ProcessingLockout)
{
if (NowAbsoluteSeconds >= HttpRetryRequestEntry.LockoutEndTimeAbsoluteSeconds)
{
// if this fails the HttpRequest's state will be failed which will cause the retry logic to kick(as expected)
bool success = HttpRetryRequest->HttpRequest->ProcessRequest();
if (success)
{
UE_LOG(LogHttp, Warning, TEXT("Retry %d on %s"), HttpRetryRequestEntry.CurrentRetryCount + 1, *(HttpRetryRequest->GetURL()));
++HttpRetryRequestEntry.CurrentRetryCount;
HttpRetryRequest->Status = FRequest::EStatus::Processing;
}
}
if (FailingCount != nullptr)
{
++(*FailingCount);
}
}
}
else
{
UE_LOG(LogHttp, Warning, TEXT("Timeout on retry %d: %s"), HttpRetryRequestEntry.CurrentRetryCount + 1, *(HttpRetryRequest->GetURL()));
bIsGreen = false;
HttpRetryRequest->Status = FHttpRetrySystem::FRequest::EStatus::FailedTimeout;
if (FailedCount != nullptr)
{
++(*FailedCount);
}
}
bool bWasCompleted = false;
bool bWasSuccessful = false;
if (HttpRetryRequest->Status == FHttpRetrySystem::FRequest::EStatus::Cancelled ||
HttpRetryRequest->Status == FHttpRetrySystem::FRequest::EStatus::FailedRetry ||
HttpRetryRequest->Status == FHttpRetrySystem::FRequest::EStatus::FailedTimeout ||
HttpRetryRequest->Status == FHttpRetrySystem::FRequest::EStatus::Succeeded)
{
bWasCompleted = true;
bWasSuccessful = HttpRetryRequest->Status == FHttpRetrySystem::FRequest::EStatus::Succeeded;
}
if (bWasCompleted)
{
HttpRetryRequest->OnProcessRequestComplete().ExecuteIfBound(HttpRetryRequest, bWasSuccessful);
}
if(bWasSuccessful)
{
if(CompletedCount != nullptr)
{
++(*CompletedCount);
}
}
if (bWasCompleted)
{
RequestList.RemoveAtSwap(index);
}
else
{
++index;
}
}
return bIsGreen;
}
FHttpRetrySystem::FManager::FHttpRetryRequestEntry::FHttpRetryRequestEntry(TSharedRef<FHttpRetrySystem::FRequest>& InHttpRequest)
: bShouldCancel(false)
, CurrentRetryCount(0)
, RequestStartTimeAbsoluteSeconds(FPlatformTime::Seconds())
, HttpRequest(InHttpRequest)
{}
bool FHttpRetrySystem::FManager::ProcessRequest(TSharedRef<FHttpRetrySystem::FRequest>& HttpRequest)
{
bool bResult = HttpRequest->ProcessRequest();
if (bResult)
{
RequestList.Add(FHttpRetryRequestEntry(HttpRequest));
}
return bResult;
}
void FHttpRetrySystem::FManager::CancelRequest(TSharedRef<FHttpRetrySystem::FRequest>& HttpRequest)
{
for (int32 i = 0; i < RequestList.Num(); ++i)
{
FHttpRetryRequestEntry& EntryRef = RequestList[i];
if(EntryRef.HttpRequest == HttpRequest)
{
EntryRef.bShouldCancel = true;
}
}
HttpRequest->CancelRequest();
/*
if (bResult)
{
RequestList.Add(FHttpRetryRequestEntry(HttpRequest));
}
return bResult;
*/
}