private async Task DoWork(string nodeTag) { try { var task = nodeTag == null || _requestExecutor.Conventions.DisableTopologyUpdates ? _requestExecutor.GetPreferredNode() : _requestExecutor.GetRequestedNode(nodeTag); (_nodeIndex, _serverNode) = await task.ConfigureAwait(false); } catch (OperationCanceledException e) { NotifyAboutError(e); _tcs.TrySetCanceled(); return; } catch (Exception e) { ConnectionStatusChanged?.Invoke(this, EventArgs.Empty); NotifyAboutError(e); _tcs.TrySetException(e); return; } var wasConnected = false; while (_cts.IsCancellationRequested == false) { try { if (Connected == false) { _url = new Uri($"{_serverNode.Url}/databases/{_database}/changes" .ToLower() .ToWebSocketPath(), UriKind.Absolute); await _client.ConnectAsync(_url, _cts.Token).ConfigureAwait(false); wasConnected = true; Interlocked.Exchange(ref _immediateConnection, 1); foreach (var counter in _counters) { counter.Value.Set(counter.Value.OnConnect()); } ConnectionStatusChanged?.Invoke(this, EventArgs.Empty); } await ProcessChanges().ConfigureAwait(false); } catch (OperationCanceledException) when(_cts.Token.IsCancellationRequested) { // disposing return; } catch (ChangeProcessingException) { continue; } catch (Exception e) { //We don't report this error since we can automatically recover from it and we can't // recover from the OnError accessing the faulty WebSocket. try { if (wasConnected) { ConnectionStatusChanged?.Invoke(this, EventArgs.Empty); } wasConnected = false; try { _serverNode = await _requestExecutor.HandleServerNotResponsive(_url.AbsoluteUri, _serverNode, _nodeIndex, e).ConfigureAwait(false); } catch (DatabaseDoesNotExistException databaseDoesNotExistException) { e = databaseDoesNotExistException; throw; } catch (Exception) { //We don't want to stop observe for changes if server down. we will wait for one to be up } if (ReconnectClient() == false) { return; } } catch { // we couldn't reconnect NotifyAboutError(e); _tcs.TrySetException(e); throw; } } finally { foreach (var confirmation in _confirmations) { confirmation.Value.TrySetCanceled(); } _confirmations.Clear(); } try { await TimeoutManager.WaitFor(TimeSpan.FromSeconds(1), _cts.Token).ConfigureAwait(false); } catch (OperationCanceledException) { return; } } }