Exemplo n.º 1
0
        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;
                }
            }
        }