Esempio n. 1
0
        public TimeoutsBatch GetTimeoutsBatch()
        {
            var retval = new TimeoutsBatch {
                DueTimeouts = new List <TimeoutData>()
            };

            IMongoCollection <TimeoutData> collection = _mongoDatabase.GetCollection <TimeoutData>(TimeoutsCollectionName);

            DateTime utcNow = DateTime.UtcNow;

            // Find all the due timeouts and put a lock on each one to prevent multiple threads/processes getting hold of the same data.
            bool doQuery = true;

            while (doQuery)
            {
                var filter1 = Builders <TimeoutData> .Filter.Eq(_ => _.Locked, false) &
                              Builders <TimeoutData> .Filter.Lte(_ => _.Time, utcNow);

                var update = Builders <TimeoutData> .Update.Set(_ => _.Locked, true);

                var result = collection.UpdateOne(filter1, update);

                if (result.ModifiedCount == 0)
                {
                    doQuery = false;
                }
                else
                {
                    var filter2 = Builders <TimeoutData> .Filter.Eq(s => s.Id, result.UpsertedId);

                    retval.DueTimeouts.Add(collection.Find(filter2).First());
                }
            }

            // Get next query time
            var nextQueryTime = DateTime.MaxValue;
            var filter        = Builders <TimeoutData> .Filter.Eq(_ => _.Time, utcNow);

            var upcomingTimeoutsRes = collection.Find(filter);

            foreach (TimeoutData upcomingTimeout in upcomingTimeoutsRes.ToList())
            {
                if (upcomingTimeout.Time < nextQueryTime)
                {
                    nextQueryTime = upcomingTimeout.Time;
                }
            }

            if (nextQueryTime == DateTime.MaxValue)
            {
                nextQueryTime = utcNow.AddMinutes(1);
            }

            retval.NextQueryTime = nextQueryTime;

            return(retval);
        }
        public TimeoutsBatch GetTimeoutsBatch()
        {
            var retval = new TimeoutsBatch {
                DueTimeouts = new List <TimeoutData>()
            };

            MongoCollection <TimeoutData> collection = _mongoDatabase.GetCollection <TimeoutData>(TimeoutsCollectionName);

            DateTime utcNow = DateTime.UtcNow;

            // Find all the due timeouts and put a lock on each one to prevent multiple threads/processes getting hold of the same data.
            bool doQuery = true;

            while (doQuery)
            {
                var args = new FindAndModifyArgs
                {
                    Query           = Query.And(Query.EQ("Locked", false), Query.LTE("Time", utcNow)),
                    Update          = Update <TimeoutData> .Set(c => c.Locked, true),
                    Upsert          = false,
                    VersionReturned = FindAndModifyDocumentVersion.Original
                };
                FindAndModifyResult result = collection.FindAndModify(args);

                if (result.ModifiedDocument == null)
                {
                    doQuery = false;
                }
                else
                {
                    retval.DueTimeouts.Add(result.GetModifiedDocumentAs <TimeoutData>());
                }
            }

            // Get next query time
            var nextQueryTime       = DateTime.MaxValue;
            var upcomingTimeoutsRes = collection.Find(Query.GT("Time", utcNow));

            foreach (TimeoutData upcomingTimeout in upcomingTimeoutsRes)
            {
                if (upcomingTimeout.Time < nextQueryTime)
                {
                    nextQueryTime = upcomingTimeout.Time;
                }
            }

            if (nextQueryTime == DateTime.MaxValue)
            {
                nextQueryTime = utcNow.AddMinutes(1);
            }

            retval.NextQueryTime = nextQueryTime;

            return(retval);
        }
        public TimeoutsBatch GetTimeoutsBatch()
        {
            var retval = new TimeoutsBatch {
                DueTimeouts = new List <TimeoutData>()
            };

            DateTime utcNow = DateTime.UtcNow;

            var nextQueryTime = DateTime.MaxValue;

            lock (_memoryCacheLock)
            {
                //var cacheItems = (from n in Cache.AsParallel() where n.Value.GetType() == typeof (TimeoutData) select new { n.Value, n.Key });

                IDictionary <string, object> cacheItems = new Dictionary <string, object>();

                foreach (var key in _provider.Keys())
                {
                    var value = _provider.Get <string, object>(key.ToString());
                    if (value.GetType() == typeof(MemoryData <IProcessManagerData>))
                    {
                        cacheItems.Add(key.ToString(), value);
                    }
                }

                foreach (var data in cacheItems)
                {
                    var timeoutData = (TimeoutData)data.Value;
                    if (timeoutData.Time <= utcNow)
                    {
                        retval.DueTimeouts.Add(timeoutData);
                    }

                    if (timeoutData.Time > utcNow && timeoutData.Time < nextQueryTime)
                    {
                        nextQueryTime = timeoutData.Time;
                    }
                }
            }

            if (nextQueryTime == DateTime.MaxValue)
            {
                nextQueryTime = utcNow.AddMinutes(1);
            }

            retval.NextQueryTime = nextQueryTime;

            return(retval);
        }
Esempio n. 4
0
        private void SetupProcessManagerFinderMock(DateTime nextTimeoutQueryTime)
        {
            var timeoutsBatch = new TimeoutsBatch
            {
                DueTimeouts =
                    new List <TimeoutData>
                {
                    new TimeoutData
                    {
                        Time             = DateTime.UtcNow.AddSeconds(-30),
                        ProcessManagerId = _pmId,
                        Id          = _tdId,
                        Destination = "TestDest"
                    }
                },
                NextQueryTime = nextTimeoutQueryTime
            };

            _mockProcessManagerFinder.Setup(i => i.GetTimeoutsBatch()).Returns(timeoutsBatch);
        }
Esempio n. 5
0
        public void InnerPoll(CancellationToken cancellationToken)
        {
            var utcNow = DateTime.UtcNow;

            if (NextQueryUtc > utcNow || cancellationToken.IsCancellationRequested)
            {
                return;
            }

            // connect to the data store and get all the expired timeouts
            TimeoutsBatch timeoutsBatch = _processManagerFinder.GetTimeoutsBatch();

            foreach (var timeoutData in timeoutsBatch.DueTimeouts)
            {
                if (cancellationToken.IsCancellationRequested)
                {
                    return;
                }

                // dispatch the timeout message
                var timeoutMsg = new TimeoutMessage(timeoutData.ProcessManagerId);
                _bus.Send(timeoutData.Destination, timeoutMsg);

                // remove dispatch timeout
                _processManagerFinder.RemoveDispatchedTimeout(timeoutData.Id);
            }

            lock (_locker)
            {
                var nextQueryTime = timeoutsBatch.NextQueryTime;

                // ensure to poll at least every minute
                var maxNextQuery = utcNow.AddMinutes(1);

                NextQueryUtc = (nextQueryTime > maxNextQuery) ? maxNextQuery : nextQueryTime;

                Logger.DebugFormat("Polling next query is at {0}.", NextQueryUtc.ToLocalTime());
            }
        }
        public TimeoutsBatch GetTimeoutsBatch()
        {
            var retval = new TimeoutsBatch {
                DueTimeouts = new List <TimeoutData>()
            };

            using (var connection = new SqlConnection(_connectionString))
            {
                connection.Open();

                // Make sure table exists
                using (var cmd = new SqlCommand())
                {
                    cmd.Connection  = connection;
                    cmd.CommandText = string.Format("IF NOT EXISTS( SELECT 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = '{0}') ", TimeoutsTableName) +
                                      string.Format("CREATE TABLE {0} (Id uniqueidentifier NOT NULL, ProcessManagerId uniqueidentifier NOT NULL, Destination varchar(250) NOT NULL, Time DateTime NOT NULL, Locked bit, Headers text);", TimeoutsTableName);
                    cmd.ExecuteNonQuery();
                }

                using (var dbTran = connection.BeginTransaction(IsolationLevel.Serializable))
                {
                    var utcNow = DateTime.UtcNow;

                    // Get timeouts due
                    string querySql = string.Format("SELECT Id, ProcessManagerId, Destination, Time, Locked, Headers  FROM  [dbo].[{0}] WHERE Locked = 0 AND Time <= @Time", TimeoutsTableName);
                    using (var cmd = new SqlCommand(querySql, connection, dbTran))
                    {
                        cmd.Parameters.AddWithValue("@Time", utcNow);

                        using (SqlDataReader reader = cmd.ExecuteReader())
                        {
                            while (reader.Read())
                            {
                                var td = new TimeoutData
                                {
                                    Destination      = reader["Destination"].ToString(),
                                    Id               = Guid.Parse(reader["Id"].ToString()),
                                    Headers          = JsonConvert.DeserializeObject <IDictionary <string, object> >(reader["Headers"].ToString()),
                                    ProcessManagerId = Guid.Parse(reader["ProcessManagerId"].ToString()),
                                    Time             = (DateTime)reader["Time"]
                                };
                                retval.DueTimeouts.Add(td);
                            }
                        }
                    }

                    // Lock records with timout due
                    string updateSql = string.Format("UPDATE  [dbo].[{0}] SET Locked = 1  WHERE Locked = 0 AND Time <= @Time", TimeoutsTableName);
                    using (var cmd = new SqlCommand(updateSql, connection, dbTran))
                    {
                        cmd.Parameters.AddWithValue("@Time", utcNow);
                        cmd.ExecuteNonQuery();
                    }

                    // Get next query time
                    var    nextQueryTime    = DateTime.MaxValue;
                    string nextQueryTimeSql = string.Format("SELECT Time  FROM  [dbo].[{0}] WHERE Time > @Time", TimeoutsTableName);
                    using (var cmd = new SqlCommand(nextQueryTimeSql, connection, dbTran))
                    {
                        cmd.Parameters.AddWithValue("@Time", utcNow);

                        using (SqlDataReader reader = cmd.ExecuteReader())
                        {
                            while (reader.Read())
                            {
                                if ((DateTime)reader["Time"] < nextQueryTime)
                                {
                                    nextQueryTime = (DateTime)reader["Time"];
                                }
                            }
                        }
                    }

                    if (nextQueryTime == DateTime.MaxValue)
                    {
                        nextQueryTime = utcNow.AddMinutes(1);
                    }

                    retval.NextQueryTime = nextQueryTime;

                    dbTran.Commit();
                }
            }

            return(retval);
        }