Microsoft.AspNet.SignalR.SqlServer.ObservableDbOperation.ExecuteReaderWithUpdates C# (CSharp) Method

ExecuteReaderWithUpdates() private method

private ExecuteReaderWithUpdates ( DbOperation>.Action processRecord ) : void
processRecord DbOperation>.Action
return void
        public void ExecuteReaderWithUpdates(Action<IDataRecord, DbOperation> processRecord)
        {
            lock (_stopLocker)
            {
                if (_disposing)
                {
                    return;
                }
                _stopHandle.Reset();
            }

            var useNotifications = _dbBehavior.StartSqlDependencyListener();

            var delays = _dbBehavior.UpdateLoopRetryDelays;

            for (var i = 0; i < delays.Count; i++)
            {
                if (i == 0 && useNotifications)
                {
                    // Reset the state to ProcessingUpdates if this is the start of the loop.
                    // This should be safe to do here without Interlocked because the state is protected
                    // in the other two cases using Interlocked, i.e. there should only be one instance of
                    // this running at any point in time.
                    _notificationState = NotificationState.ProcessingUpdates;
                }

                Tuple<int, int> retry = delays[i];
                var retryDelay = retry.Item1;
                var retryCount = retry.Item2;

                for (var j = 0; j < retryCount; j++)
                {
                    if (_disposing)
                    {
                        Stop(null);
                        return;
                    }

                    if (retryDelay > 0)
                    {
                        Trace.TraceVerbose("{0}Waiting {1}ms before checking for messages again", TracePrefix, retryDelay);

                        Thread.Sleep(retryDelay);
                    }

                    var recordCount = 0;
                    try
                    {
                        recordCount = ExecuteReader(processRecord);

                        Queried();
                    }
                    catch (Exception ex)
                    {
                        Trace.TraceError("{0}Error in SQL receive loop: {1}", TracePrefix, ex);

                        Faulted(ex);
                    }

                    if (recordCount > 0)
                    {
                        Trace.TraceVerbose("{0}{1} records received", TracePrefix, recordCount);

                        // We got records so start the retry loop again
                        i = -1;
                        break;
                    }

                    Trace.TraceVerbose("{0}No records received", TracePrefix);

                    var isLastRetry = i == delays.Count - 1 && j == retryCount - 1;

                    if (isLastRetry)
                    {
                        // Last retry loop iteration
                        if (!useNotifications)
                        {
                            // Last retry loop and we're not using notifications so just stay looping on the last retry delay
                            j = j - 1;
                        }
                        else
                        {
                            // No records after all retries, set up a SQL notification
                            try
                            {
                                Trace.TraceVerbose("{0}Setting up SQL notification", TracePrefix);

                                recordCount = ExecuteReader(processRecord, command =>
                                {
                                    _dbBehavior.AddSqlDependency(command, e => SqlDependency_OnChange(e, processRecord));
                                });

                                Queried();

                                if (recordCount > 0)
                                {
                                    Trace.TraceVerbose("{0}Records were returned by the command that sets up the SQL notification, restarting the receive loop", TracePrefix);

                                    i = -1;
                                    break; // break the inner for loop
                                }
                                else
                                {
                                    var previousState = Interlocked.CompareExchange(ref _notificationState, NotificationState.AwaitingNotification,
                                        NotificationState.ProcessingUpdates);

                                    if (previousState == NotificationState.AwaitingNotification)
                                    {
                                        Trace.TraceError("{0}A SQL notification was already running. Overlapping receive loops detected, this should never happen. BUG!", TracePrefix);

                                        return;
                                    }

                                    if (previousState == NotificationState.NotificationReceived)
                                    {
                                        // Failed to change _notificationState from ProcessingUpdates to AwaitingNotification, it was already NotificationReceived

                                        Trace.TraceVerbose("{0}The SQL notification fired before the receive loop returned, restarting the receive loop", TracePrefix);

                                        i = -1;
                                        break; // break the inner for loop
                                    }
                                    
                                }

                                Trace.TraceVerbose("{0}No records received while setting up SQL notification", TracePrefix);

                                // We're in a wait state for a notification now so check if we're disposing
                                lock (_stopLocker)
                                {
                                    if (_disposing)
                                    {
                                        _stopHandle.Set();
                                    }
                                }
                            }
                            catch (Exception ex)
                            {
                                Trace.TraceError("{0}Error in SQL receive loop: {1}", TracePrefix, ex);
                                Faulted(ex);

                                // Re-enter the loop on the last retry delay
                                j = j - 1;

                                if (retryDelay > 0)
                                {
                                    Trace.TraceVerbose("{0}Waiting {1}ms before checking for messages again", TracePrefix, retryDelay);

                                    Thread.Sleep(retryDelay);
                                }
                            }
                        }
                    }
                }
            }

            Trace.TraceVerbose("{0}Receive loop exiting", TracePrefix);
        }

Usage Example

コード例 #1
0
        private void Receive(object state)
        {
            var tcs = (TaskCompletionSource <object>)state;

            if (!_lastPayloadId.HasValue)
            {
                var lastPayloadIdOperation = new DbOperation(_connectionString, _maxIdSql, _trace)
                {
                    TracePrefix = _tracePrefix
                };

                try
                {
                    _lastPayloadId = (long?)lastPayloadIdOperation.ExecuteScalar();
                    Queried();

                    // Complete the StartReceiving task as we've successfully initialized the payload ID
                    tcs.TrySetResult(null);
                }
                catch (Exception ex)
                {
                    tcs.TrySetException(ex);
                    return;
                }
            }

            // NOTE: This is called from a BG thread so any uncaught exceptions will crash the process
            lock (this)
            {
                if (_disposed)
                {
                    return;
                }

                var parameter = _dbProviderFactory.CreateParameter();
                parameter.ParameterName = "PayloadId";
                parameter.Value         = _lastPayloadId.Value;

                _dbOperation = new ObservableDbOperation(_connectionString, _selectSql, _trace, parameter)
                {
                    TracePrefix = _tracePrefix
                };
            }

            _dbOperation.Queried += () => Queried();
            _dbOperation.Faulted += ex => Faulted(ex);
            _dbOperation.Changed += () =>
            {
                Trace.TraceInformation("{0}Starting receive loop again to process updates", _tracePrefix);

                _dbOperation.ExecuteReaderWithUpdates(ProcessRecord);
            };

            _dbOperation.ExecuteReaderWithUpdates(ProcessRecord);

            _trace.TraceWarning("{0}SqlReceiver.Receive returned", _tracePrefix);
        }
All Usage Examples Of Microsoft.AspNet.SignalR.SqlServer.ObservableDbOperation::ExecuteReaderWithUpdates