Represents a BSON document that can be used where an IMongoFields is expected.
Inheritance: BsonDocument, IMongoFields
Exemple #1
0
        /// <summary>
        /// Get a non running message from queue
        /// </summary>
        /// <param name="query">query where top level fields do not contain operators. Lower level fields can however. eg: valid {a: {$gt: 1}, "b.c": 3}, invalid {$and: [{...}, {...}]}</param>
        /// <param name="resetRunning">duration before this message is considered abandoned and will be given with another call to Get()</param>
        /// <param name="wait">duration to keep polling before returning null</param>
        /// <param name="poll">duration between poll attempts</param>
        /// <returns>message or null</returns>
        /// <exception cref="ArgumentNullException">query is null</exception>
        public BsonDocument Get(QueryDocument query, TimeSpan resetRunning, TimeSpan wait, TimeSpan poll)
        {
            if (query == null) throw new ArgumentNullException("query");

            //reset stuck messages
            collection.Update(
                new QueryDocument { { "running", true }, { "resetTimestamp", new BsonDocument("$lte", DateTime.UtcNow) } },
                new UpdateDocument("$set", new BsonDocument("running", false)),
                UpdateFlags.Multi
            );

            var builtQuery = new QueryDocument("running", false);
            foreach (var field in query)
                builtQuery.Add("payload." + field.Name, field.Value);

            builtQuery.Add("earliestGet", new BsonDocument("$lte", DateTime.UtcNow));

            var resetTimestamp = DateTime.UtcNow;
            try
            {
                resetTimestamp += resetRunning;
            }
            catch (ArgumentOutOfRangeException)
            {
                resetTimestamp = resetRunning > TimeSpan.Zero ? DateTime.MaxValue : DateTime.MinValue;
            }

            var sort = new SortByDocument { { "priority", 1 }, { "created", 1 } };
            var update = new UpdateDocument("$set", new BsonDocument { { "running", true }, { "resetTimestamp", resetTimestamp } });
            var fields = new FieldsDocument("payload", 1);

            var end = DateTime.UtcNow;
            try
            {
                end += wait;
            }
            catch (ArgumentOutOfRangeException)
            {
                end = wait > TimeSpan.Zero ? DateTime.MaxValue : DateTime.MinValue;
            }

            while (true)
            {
                var message = collection.FindAndModify(builtQuery, sort, update, fields, false, false).ModifiedDocument;
                if (message != null)
                    //using merge without overwriting so a possible id in payload doesnt wipe it out the generated one
                    return new BsonDocument("id", message["_id"]).Merge(message["payload"].AsBsonDocument);

                if (DateTime.UtcNow >= end)
                    return null;

                try
                {
                    Thread.Sleep(poll);
                }
                catch (ArgumentOutOfRangeException)
                {
                    poll = poll < TimeSpan.Zero ? TimeSpan.Zero : TimeSpan.FromMilliseconds(int.MaxValue);

                    Thread.Sleep(poll);
                }
            }
        }
        public void TestFieldsDocumentConstructor()
        {
            var document1 = new FieldsDocument(dictionary);
            var document2 = new FieldsDocument(hashtable);
            var document3 = new FieldsDocument(idictionaryNonGeneric);
            var document4 = new FieldsDocument(idictionary);

            Assert.AreEqual("Dictionary<string, object>", document1["type"].AsString);
            Assert.AreEqual("Hashtable", document2["type"].AsString);
            Assert.AreEqual("IDictionary", document3["type"].AsString);
            Assert.AreEqual("IDictionary<string, object>", document4["type"].AsString);
        }
        /// <summary>
        /// Get a non running message from queue
        /// </summary>
        /// <param name="query">query where top level fields do not contain operators. Lower level fields can however. eg: valid {a: {$gt: 1}, "b.c": 3}, invalid {$and: [{...}, {...}]}</param>
        /// <param name="resetRunning">duration before this message is considered abandoned and will be given with another call to Get()</param>
        /// <param name="wait">duration to keep polling before returning null</param>
        /// <param name="poll">duration between poll attempts</param>
        /// <param name="approximateWait">whether to fluctuate the wait time randomly by +-10 percent. This ensures Get() calls seperate in time when multiple Queues are used in loops started at the same time</param>
        /// <returns>message or null</returns>
        /// <exception cref="ArgumentNullException">query is null</exception>
        public Message Get(QueryDocument query, TimeSpan resetRunning, TimeSpan wait, TimeSpan poll, bool approximateWait)
        {
            if (query == null)
                throw new ArgumentNullException ("query");

            //reset stuck messages
            collection.Update(
                new QueryDocument { { "running", true }, { "resetTimestamp", new BsonDocument("$lte", DateTime.UtcNow) } },
                new UpdateDocument("$set", new BsonDocument("running", false)),
                UpdateFlags.Multi
            );

            var builtQuery = new QueryDocument("running", false);
            foreach (var field in query)
                builtQuery.Add("payload." + field.Name, field.Value);

            builtQuery.Add("earliestGet", new BsonDocument("$lte", DateTime.UtcNow));

            var resetTimestamp = DateTime.UtcNow;
            try
            {
                resetTimestamp += resetRunning;
            }
            catch (ArgumentOutOfRangeException)
            {
                resetTimestamp = resetRunning > TimeSpan.Zero ? DateTime.MaxValue : DateTime.MinValue;
            }

            var sort = new SortByDocument { { "priority", 1 }, { "created", 1 } };
            var update = new UpdateDocument("$set", new BsonDocument { { "running", true }, { "resetTimestamp", resetTimestamp } });
            var fields = new FieldsDocument { { "payload", 1 }, { "streams", 1 } };

            var end = DateTime.UtcNow;
            try
            {
                if (approximateWait)
                    //fluctuate randomly by 10 percent
                    wait += TimeSpan.FromMilliseconds(wait.TotalMilliseconds * GetRandomDouble(-0.1, 0.1));

                end += wait;
            }
            catch (Exception e)
            {
                if (!(e is OverflowException) && !(e is ArgumentOutOfRangeException))
                    throw e;//cant cover

                end = wait > TimeSpan.Zero ? DateTime.MaxValue : DateTime.MinValue;
            }

            while (true)
            {
                var findModifyArgs = new FindAndModifyArgs { Query = builtQuery, SortBy = sort, Update = update, Fields = fields, Upsert = false };

                var message = collection.FindAndModify(findModifyArgs).ModifiedDocument;
                if (message != null)
                {
                    var handleStreams = new List<KeyValuePair<BsonValue, Stream>>();
                    var messageStreams = new Dictionary<string, Stream>();
                    foreach (var streamId in message["streams"].AsBsonArray)
                    {
                        var fileInfo = gridfs.FindOneById(streamId);

                        var stream = fileInfo.OpenRead();

                        handleStreams.Add(new KeyValuePair<BsonValue, Stream>(streamId, stream));
                        messageStreams.Add(fileInfo.Name, stream);
                    }

                    var handle = new Handle(message["_id"].AsObjectId, handleStreams);
                    return new Message(handle, message["payload"].AsBsonDocument, messageStreams);
                }

                if (DateTime.UtcNow >= end)
                    return null;

                try
                {
                    Thread.Sleep(poll);
                }
                catch (ArgumentOutOfRangeException)
                {
                    if (poll < TimeSpan.Zero)
                        poll = TimeSpan.Zero;
                    else
                        poll = TimeSpan.FromMilliseconds(int.MaxValue);

                    Thread.Sleep(poll);
                }

                if (DateTime.UtcNow >= end)
                    return null;
            }
        }