Skip to content

Instantly share code, notes, and snippets.

@TomasBouda
Created April 11, 2023 20:04
Show Gist options
  • Save TomasBouda/a2fda5138319abec7823829da5fdcb79 to your computer and use it in GitHub Desktop.
Save TomasBouda/a2fda5138319abec7823829da5fdcb79 to your computer and use it in GitHub Desktop.
using System.Net;
using System.Security;
using Polly;
using Serilog;
using Microsoft.AspNet.SignalR.Client;
namespace Test.SignalR;
/// <summary>
/// SignalR Hub client implementation for ASP.NET
/// </summary>
public class TestHubClient : IAsyncDisposable
{
private HubConnection _connection;
private IHubProxy _hubProxy;
public event Func<Task>? Disconnected;
public string HubUrl { get; }
public ILogger Logger { get; }
public ConnectionState State => _connection.State;
private bool _tryingToReconnect;
public TestHubClient(string hubUrl, SecureString key, ILogger? logger = null)
{
HubUrl = hubUrl;
Logger = logger ?? Log.Logger;
_connection = new HubConnection(HubUrl, false);
_hubProxy = _connection.CreateHubProxy("testHub");
// Setup events
_connection.Reconnecting += OnReconnecting;
_connection.Reconnected += OnReconnected;
_connection.Closed += OnClosed;
_connection.Error += OnError;
_connection.ConnectionSlow += OnConnectionSlow;
}
/// <summary>
/// When invoked, client will automatically try to reconnect when connection is closed
/// </summary>
public void WithAutomaticReconnect()
{
Disconnected += async () =>
{
if (!_tryingToReconnect)
{
Logger.Debug("Reconnecting after 5 seconds");
await Task.Delay(TimeSpan.FromSeconds(5));
await ConnectAsync(CancellationToken.None);
}
};
}
private void OnClosed()
{
Logger.Warning("Disconnected from hub: {HubUrl}", HubUrl);
Disconnected?.Invoke();
}
private void OnReconnected()
{
Logger.Information("Reconnected to hub: {HubUrl}", HubUrl);
}
private void OnReconnecting()
{
Logger.Debug("Reconnecting to hub: {HubUrl}", HubUrl);
}
private void OnError(Exception exception)
{
Logger.Warning(exception, "Error occured in hub: {HubUrl}", HubUrl);
}
private void OnConnectionSlow()
{
Logger.Warning("Slow connection to hub: {HubUrl}", HubUrl);
}
public async Task ConnectAsync(CancellationToken ct)
{
try
{
_tryingToReconnect = true;
// Here we setup Polly policy to retry connection forever
// with wait time between each attempt increasing to maximum of 1 minute
await Policy
.Handle<Exception>()
.WaitAndRetryForeverAsync(
retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)).Clamp(TimeSpan.FromMinutes(1)),
(exception, timespan) =>
{
Logger.Warning(exception, "Error occured while trying to connect to hub {HubUrl}. Another attempt after {TimeSpan}", HubUrl, timespan);
})
.ExecuteAsync(async () =>
{
ct.ThrowIfCancellationRequested();
Logger.Debug("Connecting to {HubUrl}", HubUrl);
await _connection.Start();
Logger.Information("Connected to hub: {HubUrl}", HubUrl);
});
}
finally
{
_tryingToReconnect = false;
}
}
public Task DisconnectAsync()
{
_connection.Stop();
return Task.CompletedTask;
}
public ValueTask DisposeAsync()
{
_connection.Dispose();
return ValueTask.CompletedTask;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment