Skip to content

Commit

Permalink
Fix memory leak on error reconnection
Browse files Browse the repository at this point in the history
  • Loading branch information
Marfusios committed Sep 7, 2023
1 parent 233e1bd commit df2e007
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 6 deletions.
15 changes: 11 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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();
```
Expand All @@ -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
Expand Down Expand Up @@ -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), <[email protected]>)
13 changes: 11 additions & 2 deletions src/Websocket.Client/WebsocketClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -195,6 +197,7 @@ public void Dispose()
_messagesTextToSendQueue.Writer.Complete();
_messagesBinaryToSendQueue.Writer.Complete();
_lastChanceTimer?.Dispose();
_errorReconnectTimer?.Dispose();
_cancellation?.Cancel();
_cancellationTotal?.Cancel();
_client?.Abort();
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit df2e007

Please sign in to comment.