private void RetryOrStopIfNecessary(HttpStatusCode statusCode)
        {
            if (!IsRunning || ((int)statusCode >= 200 && (int)statusCode <= 299))
            {
                return;
            }

            if (!Continuous)
            {
                _workExecutor.StartNew(Stop);
                return;
            }

            if (!Misc.IsTransientError(statusCode))
            {
                //
                Log.To.ChangeTracker.I(Tag, String.Format
                                           ("{0} got a non-transient error ({1}), stopping NOW...", this, statusCode));
                _workExecutor.StartNew(Stop);
                return;
            }

            Log.To.ChangeTracker.I(Tag, "{0} transient error ({1}) detected, sleeping for {2}ms...", this,
                                   statusCode, Backoff.GetSleepTime().TotalMilliseconds);
            Backoff.DelayAppropriateAmountOfTime().ContinueWith(t => PerformRetry(true));
        }
        private void RetryOrStopIfNecessary(Exception e)
        {
            if (!IsRunning)
            {
                return;
            }

            if (e == null)
            {
                // No error occurred, keep going if continuous
                if (Continuous)
                {
                    PerformRetry(false);
                }
                else
                {
                    _workExecutor.StartNew(Stop);
                }

                return;
            }

            Error = Misc.Flatten(e).First();
            string statusCode;

            if (Misc.IsTransientNetworkError(e, out statusCode))
            {
                // Transient error occurred in a replication -> RETRY or STOP
                if (!Continuous && !Backoff.CanContinue)
                {
                    // Give up for non-continuous
                    Log.To.ChangeTracker.I(Tag, "{0} transient error ({1}) detected, giving up NOW...", this,
                                           statusCode);
                    _workExecutor.StartNew(Stop);
                    return;
                }

                // Keep retrying for continuous
                Log.To.ChangeTracker.I(Tag, "{0} transient error ({1}) detected, sleeping for {2}ms...", this,
                                       statusCode, Backoff.GetSleepTime().TotalMilliseconds);

                Backoff.DelayAppropriateAmountOfTime().ContinueWith(t => PerformRetry(true));
                return;
            }

            if (String.IsNullOrEmpty(statusCode))
            {
                Log.To.ChangeTracker.I(Tag, String.Format
                                           ("{0} got an exception, stopping NOW...", this), e);
            }
            else
            {
                Log.To.ChangeTracker.I(Tag, String.Format
                                           ("{0} got a non-transient error ({1}), stopping NOW...", this, statusCode));
            }

            // Non-transient error occurred in a continuous replication -> STOP
            _workExecutor.StartNew(Stop);
        }
        private Task ChangeFeedResponseHandler(Task <HttpResponseMessage> responseTask)
        {
            if (ResponseFailed(responseTask))
            {
                return(Task.FromResult(false));
            }

            var response = responseTask.Result;

            UpdateServerType(response);

            if (response.Content == null)
            {
                throw Misc.CreateExceptionAndLog(Log.To.ChangeTracker, response.StatusCode.GetStatusCode(), Tag,
                                                 "Got empty change tracker response");
            }

            Log.To.ChangeTracker.D(Tag, "Getting stream from change tracker response");
            return(response.Content.ReadAsStreamAsync().ContinueWith((Task <Stream> t) =>
            {
                try {
                    var result = _responseLogic.ProcessResponseStream(t?.Result, changesFeedRequestTokenSource == null ? CancellationToken.None : changesFeedRequestTokenSource.Token);
                    Backoff.ResetBackoff();
                    if (result == ChangeTrackerResponseCode.ChangeHeartbeat)
                    {
                        Heartbeat = _responseLogic.Heartbeat;
                        _workExecutor.StartNew(Run);
                    }
                } catch (CouchbaseLiteException e) {
                    if (e.Code == StatusCode.BadJson)
                    {
                        if (Backoff.CanContinue)
                        {
                            Log.To.ChangeTracker.W(Tag, "{0} Couldn't parse JSON from remote, " +
                                                   "retrying in {1}ms", this, Backoff.GetSleepTime().TotalMilliseconds);
                            Backoff.DelayAppropriateAmountOfTime().ContinueWith(t1 => {
                                Log.To.ChangeTracker.I(Tag, "{0} retrying NOW...", this);
                                _workExecutor.StartNew(Run);
                            });
                        }
                        else
                        {
                            RetryOrStopIfNecessary(e);
                        }
                    }
                } catch (Exception e) {
                    RetryOrStopIfNecessary(e);
                } finally {
                    Misc.SafeDispose(ref changesFeedRequestTokenSource);
                    response.Dispose();
                }
            }));
        }