Retry logic for HTTP Requests

Hello,

I want to have my dedicated server make an API call. This is well-documented and can be done as follows (which works perfectly fine):

void AMyGame::CallAPI()
{
	FString apiUrl= "http://myApi/endpoint";

	TSharedRef<IHttpRequest, ESPMode::ThreadSafe> Request = HttpModule::Get().CreateRequest();

	Request->SetURL(apiUrl);
	Request->SetVerb("POST");
	Request->SetHeader("Content-Type", TEXT("application/json"));
	Request->SetTimeout(5);
	Request->AMyGame().BindUObject(this, &AMyGame::OnRequestResponse);
	Request->ProcessRequest();
}

However, if the API call fails, there is no retry logic. Because of the use case of this API call, I need to add retry logic. I would like to do this using tools that Unreal has already included. I noticed specifically the HttpRetrySystem included in the source code. What I’ve come up with so far is this:

void AMyGame::CallAPI()
{
	FString apiUrl= "http://myApi/endpoint";

	FManager RetrySystem = FHttpRetrySystem::FManager(5, 1);
	TSharedRef<class FHttpRetrySystem::FRequest, ESPMode::ThreadSafe> Request = RetrySystem.CreateRequest();

	Request->SetURL(apiUrl);
	Request->SetVerb("POST");
	Request->SetHeader("Content-Type", TEXT("application/json"));
	Request->SetTimeout(5);
	Request->AMyGame().BindUObject(this, &AMyGame::OnRequestResponse);
	Request->ProcessRequest();
}

For context, the ‘5’ is for RetryLimitCountDefault and ‘1’ is for RetryTimeoutRelativeSecondsDefault. In the source code, the RetrySystem CreateRequest is implemented as:

TSharedRef<FHttpRetrySystem::FRequest, ESPMode::ThreadSafe> FHttpRetrySystem::FManager::CreateRequest(
	const FRetryLimitCountSetting& InRetryLimitCountOverride,
	const FRetryTimeoutRelativeSecondsSetting& InRetryTimeoutRelativeSecondsOverride,
	const FRetryResponseCodes& InRetryResponseCodes,
	const FRetryVerbs& InRetryVerbs,
	const FRetryDomainsPtr& InRetryDomains)
{
	return MakeShareable(new FRequest(
		*this,
		FHttpModule::Get().CreateRequest(),
		InRetryLimitCountOverride,
		InRetryTimeoutRelativeSecondsOverride,
		InRetryResponseCodes,
		InRetryVerbs,
		InRetryDomains
		));
}

which basically creates a request just like the original snippet but encapsulates it with some retry logic.

The reason I am posting is 1) I couldn’t find any other documentation/information about this topic elsewhere, and 2) I’m actually not sure this works properly so I would love to hear if anyone has thoughts or experience about/with this.

Thank you!

One thing that wasn’t clear to me at first was that you need to register for ticks so that you can constantly call RetrySystem.Update() (from each Tick) or you won’t get callbacks.

// MyHttp.h
class MyHttp : public FTickerObjectBase {
public:
  virtual bool Tick(float DeltaTime) override;

private:
  TUniquePtr<FHttpRetrySystem::FManager> HttpRetrySystem;
}
// MyHttp.cpp
MyHttp::MyHttp() : FTickerObjectBase(0.0f, FBackgroundableTicker::GetCoreTicker()) {
  HttpRetrySystem = MakeUnique<FHttpRetrySystem::FManager>(4, 10);
}

...

bool MyHttp::Tick(float DeltaTime) {
  HttpRetrySystem.IsValid()) {
    HttpRetrySystem->Update();
  }

  return true;
}