diff --git a/README.md b/README.md index 9216157..a8f7c7d 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,7 @@ But use it with caution, on every reconnection there will be a new instance. It is possible to change the remote server URL dynamically. Example: -```chsarp +```csharp client.Url = new Uri("wss://my_new_url");; await client.Reconnect(); ``` @@ -84,13 +84,20 @@ await client.Reconnect(); A built-in reconnection invokes after 1 minute (default) of not receiving any messages from the server. It is possible to configure that timeout via `communicator.ReconnectTimeout`. -Also, a stream `ReconnectionHappened` sends information about a type of reconnection. +In addition, a stream `ReconnectionHappened` sends information about the type of reconnection. However, if you are subscribed to low-rate channels, you will likely encounter that timeout - higher it to a few minutes or implement `ping-pong` interaction on your own every few seconds. In the case of a remote server outage, there is a built-in functionality that slows down reconnection requests (could be configured via `client.ErrorReconnectTimeout`, the default is 1 minute). -Beware that you **need to resubscribe to channels** after reconnection happens. You should subscribe to `ReconnectionHappened` stream and send subscription requests. +Usually, websocket servers do not keep a persistent connection between reconnections. Every new connection creates a new session. +Because of that, you most likely **need to resubscribe to channels/groups/topics** inside `ReconnectionHappened` stream. + +```csharp +client.ReconnectionHappened.Subscribe(info => { + client.Send("{type: subscribe, topic: xyz}") +}); +``` ### Multi-threading @@ -227,5 +234,5 @@ with an example how to ignore/discard buffered messages and always process only ### Available for help -I do consulting, please don't hesitate to contact me if you have a custom solution you would like me to implement +I do consulting, please don't hesitate to contact me if you need a paid help ([web](http://mkotas.cz/), [nostr](https://snort.social/p/npub1dd668dyr9un9nzf9fjjkpdcqmge584c86gceu7j97nsp4lj2pscs0xk075), ) diff --git a/src/Websocket.Client/WebsocketClient.cs b/src/Websocket.Client/WebsocketClient.cs index 1e1fb3d..e0c2baa 100644 --- a/src/Websocket.Client/WebsocketClient.cs +++ b/src/Websocket.Client/WebsocketClient.cs @@ -27,6 +27,8 @@ public partial class WebsocketClient : IWebsocketClient private Timer? _lastChanceTimer; private DateTime _lastReceivedMsg = DateTime.UtcNow; + private Timer? _errorReconnectTimer; + private bool _disposing; private bool _reconnecting; private bool _stopping; @@ -195,6 +197,7 @@ public void Dispose() _messagesTextToSendQueue.Writer.Complete(); _messagesBinaryToSendQueue.Writer.Complete(); _lastChanceTimer?.Dispose(); + _errorReconnectTimer?.Dispose(); _cancellation?.Cancel(); _cancellationTotal?.Cancel(); _client?.Abort(); @@ -417,11 +420,17 @@ private async Task StartClient(Uri uri, CancellationToken token, ReconnectionTyp var timeout = ErrorReconnectTimeout.Value; _logger.LogError(e, L("Exception while connecting. " + "Waiting {timeout} sec before next reconnection try. Error: '{error}'"), Name, timeout.TotalSeconds, e.Message); - await Task.Delay(timeout, token).ConfigureAwait(false); - await Reconnect(ReconnectionType.Error, false, e).ConfigureAwait(false); + _errorReconnectTimer?.Dispose(); + _errorReconnectTimer = new Timer(ReconnectOnError, e, timeout, Timeout.InfiniteTimeSpan); } } + private void ReconnectOnError(object? state) + { + // await Task.Delay(timeout, token).ConfigureAwait(false); + _ = Reconnect(ReconnectionType.Error, false, state as Exception).ConfigureAwait(false); + } + private bool IsClientConnected() { return _client?.State == WebSocketState.Open;