Skip to content

Commit

Permalink
chore: Make initialization success event parameter reflect the initia…
Browse files Browse the repository at this point in the history
…l config fetch (#169)

* set flag to success instead of changing flow

* Collapse 500 errors to one set - and set initialization to failure if the first request is a 500 or invalid

* Update tests

* Don't upgrade test apps for test harness yet

* Don't immediately retry failed config requests

This causes issues with the test harness - and resulting in a bad test failure because of the SDK retrying the request on >= 500 error response codes.

* retryonce for legacy testing

* Use previous logic for setting config polling delay

* Set initialized on any successful config call
  • Loading branch information
JamieSinn authored Dec 18, 2024
1 parent e99d586 commit 63841da
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 11 deletions.
5 changes: 3 additions & 2 deletions DevCycle.SDK.Server.Common/Policies/ClientPolicy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,20 @@ public class ClientPolicy
{
public AsyncPolicyWrap<RestResponse> ExponentialBackoffRetryPolicyWithTimeout { get; }
public AsyncRetryPolicy<RestResponse> RetryOncePolicy { get; }
public AsyncTimeoutPolicy TimeoutPolicy { get; }
private static ClientPolicy _instance = new ClientPolicy();

private ClientPolicy()
{
AsyncTimeoutPolicy timeoutPolicy = Policy.TimeoutAsync(5, TimeoutStrategy.Pessimistic);
TimeoutPolicy = Policy.TimeoutAsync(5, TimeoutStrategy.Pessimistic);
AsyncRetryPolicy<RestResponse> exponentialBackoffRetryPolicy = Policy
.HandleResult<RestResponse>(res => (int)res.StatusCode >= 500)
.WaitAndRetryAsync(5, retryAttempt => {
var delay = Math.Pow(2, retryAttempt) * 100;
var randomSum = delay * 0.2 * new Random().NextDouble();
return TimeSpan.FromMilliseconds(delay + randomSum);
});
ExponentialBackoffRetryPolicyWithTimeout = exponentialBackoffRetryPolicy.WrapAsync(timeoutPolicy);
ExponentialBackoffRetryPolicyWithTimeout = exponentialBackoffRetryPolicy.WrapAsync(TimeoutPolicy);

RetryOncePolicy = Policy
.HandleResult<RestResponse>(res => (int)res.StatusCode >= 500)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ private Tuple<EnvironmentConfigManager, MockHttpMessageHandler, MockedRequest> g
var cfgManager = new EnvironmentConfigManager(sdkKey, new DevCycleLocalOptions(),
loggerFactory, new LocalBucketing(), restClientOptions: new DevCycleRestClientOptions()
{ ConfigureMessageHandler = _ => mockHttp },
initializedHandler: (isError && !isRetryableError)
? DidNotInitializeSubscriber
initializedHandler: isError
? (isRetryableError ? DidInitializeSubscriberFailFirstConfigFetch : DidNotInitializeSubscriber)
: DidInitializeSubscriber);

return new Tuple<EnvironmentConfigManager, MockHttpMessageHandler, MockedRequest>(cfgManager, mockHttp,
Expand Down Expand Up @@ -111,6 +111,12 @@ private void DidInitializeSubscriber(object o, DevCycleEventArgs e)
Assert.IsTrue(e.Success);
Assert.AreEqual(0, e.Errors.Count);
}

private void DidInitializeSubscriberFailFirstConfigFetch(object o, DevCycleEventArgs e)
{
Assert.IsFalse(e.Success);
Assert.AreEqual(0, e.Errors.Count);
}

private void DidNotInitializeSubscriber(object o, DevCycleEventArgs e)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ public void Dispose()

private void OnInitialized(DevCycleEventArgs e)
{
Initialized = true;
Initialized = e.Success;
initializedHandler?.Invoke(this, e);
}

Expand Down Expand Up @@ -157,13 +157,18 @@ private async Task FetchConfigAsyncWithTask(uint lastmodified = 0)
switch (res.StatusCode)
{
// Status code of 0 means some other error (like a network error) occurred
case >= HttpStatusCode.InternalServerError or 0 when Config != null:
logger.LogError(res.ErrorException,
"Failed to download config, using cached version: {ConfigEtag}, {Lastmodified}", configEtag,
configLastModified);
break;
case >= HttpStatusCode.InternalServerError or 0:
logger.LogError(res.ErrorException, "Failed to download DevCycle config");
if (Config != null)
{
logger.LogError(res.ErrorException,
"Failed to download config, using cached version: {ConfigEtag}, {Lastmodified}", configEtag,
configLastModified);
}
else
{
initializationEvent.Success = false;
logger.LogError(res.ErrorException, "Failed to download initial DevCycle config");
}
break;
case >= HttpStatusCode.BadRequest:
{
Expand Down Expand Up @@ -232,8 +237,10 @@ private async Task FetchConfigAsyncWithTask(uint lastmodified = 0)
localBucketing.StoreConfig(sdkKey, res.Content);
configEtag = etag;
configLastModified = lastModified;
Config = res.Content;
logger.LogDebug("Config successfully initialized with etag: {ConfigEtag}, {lastmodified}",
configEtag, configLastModified);
Initialized = true;
}
catch (Exception e)
{
Expand Down

0 comments on commit 63841da

Please sign in to comment.