Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Retry field not used correctly #92

Open
thorstenfleischmann opened this issue Jan 12, 2023 · 5 comments
Open

Retry field not used correctly #92

thorstenfleischmann opened this issue Jan 12, 2023 · 5 comments

Comments

@thorstenfleischmann
Copy link
Contributor

thorstenfleischmann commented Jan 12, 2023

Even though the retry field is read it seems like it is not really used for the reconnection time.

Here the field is read to _retryDelay:

else if (result.IsRetryField)
{
if (long.TryParse(result.GetValueAsString(), out var retry))
{
_retryDelay = TimeSpan.FromMilliseconds(retry);
}
}

But _retryDelay is not really used for the reconnection time:

private async Task MaybeWaitWithBackOff() {
if (_retryDelay.TotalMilliseconds > 0)
{
TimeSpan sleepTime = _backOff.GetNextBackOff();
if (sleepTime.TotalMilliseconds > 0) {
_logger.Info("Waiting {0} milliseconds before reconnecting...", sleepTime.TotalMilliseconds);
BackOffDelay = sleepTime;
await Task.Delay(sleepTime);
}
}
}

Instead it is only passed initially for construction of ExponentialBackoffWithDecorrelation:

_backOff = new ExponentialBackoffWithDecorrelation(_retryDelay, _configuration.MaxRetryDelay);

The _minimumDelay in ExponentialBackoffWithDecorrelation is never updated

@thorstenfleischmann
Copy link
Contributor Author

Having the SSE retry field combined with the "ExponentialBackOffWithDecorrelation", it is hard to tell what the expected behaviour is. If the server sends a retry duration I would expect that the reconnect time is never less then the received retry duration.

Even better: if there was a retry duration received from the server do not use the exponential back off strategy. Instead just use the retry time received from the sse server.

@eli-darkly
Copy link
Contributor

eli-darkly commented Jan 12, 2023

It does look like the current logic is incorrect, but I would have to think more on what the most logical behavior would be, because we can't look to the SSE specification in this case; the spec does not say anything at all about backoff/jitter, so it has no opinion on whether or not that should be applied to a server-sent retry value.

@eli-darkly
Copy link
Contributor

I am skeptical about entirely turning off the backoff/jitter behavior in this scenario. That would mean that any server that ever sends a retry: field is setting itself up for a thundering-herd situation the next time there's a network interruption, as every client would end up reconnecting at basically the same time.

@thorstenfleischmann
Copy link
Contributor Author

Good point!

A simple solution for me would be to just recreate the ExponentialBackoffWithDecorrelation with the retry-field as new minimum.

I think it could be as easy as adding _backOff = new ExponentialBackoffWithDecorrelation(_retryDelay, _configuration.MaxRetryDelay); to line 413:

else if (result.IsRetryField)
{
if (long.TryParse(result.GetValueAsString(), out var retry))
{
_retryDelay = TimeSpan.FromMilliseconds(retry);
}
}

The behaviour if the new minimum exceeds the old maximum also seems to be reasonable.

@eli-darkly
Copy link
Contributor

Yes, that's what I was thinking too. I think this was just an oversight. We're in process of writing a new 6.0 version of dotnet-eventsource that would not have this issue, but we should be able to do this fix in 5.x as well.

(However, please note that the way the ExponentialBackoffWithDecorrelation logic currently works, the base retry value is not really the minimum— because the random jitter is subtracted, rather than added.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants