public async Task Remove_WhenConcurrentDeletesUsingDtc_OnlyOneOperationShouldSucceed()
        {
            var persister = new TimeoutPersister(store);
            var timeoutData = new TimeoutData();
            await persister.Add(timeoutData, new ContextBag());

            var documentRemoved = new CountdownEvent(2);

            var t1 = Task.Run(async () =>
            {
                using (var tx = new TransactionScope(TransactionScopeOption.RequiresNew, TransactionScopeAsyncFlowOption.Enabled))
                {
                    var result = await persister.TryRemove(timeoutData.Id, new ContextBag());
                    documentRemoved.Signal(1);
                    documentRemoved.Wait();
                    tx.Complete();
                    return result;
                }
            });

            var t2 = Task.Run(async () =>
            {
                using (var tx = new TransactionScope(TransactionScopeOption.RequiresNew, TransactionScopeAsyncFlowOption.Enabled))
                {
                    var result = await persister.TryRemove(timeoutData.Id, new ContextBag());
                    documentRemoved.Signal(1);
                    documentRemoved.Wait();
                    tx.Complete();
                    return result;
                }
            });

            Assert.IsTrue(await t1 | await t2, "the document should be deleted");
            Assert.IsFalse(t1.Result && t2.Result, "only one operation should complete successfully");
        }
Example #2
0
        public void TryRemove_NonExistentId_ReturnsFalseOutIsNull()
        {
            TimeoutData data;
            var         result = _persister.TryRemove(Guid.NewGuid().ToString(), out data);

            result.Should().BeFalse();
            data.Should().BeNull();
        }
        public void Should_return_the_correct_headers()
        {
            var persister = new TimeoutPersister
            {
                DocumentStore = store,
                EndpointName  = "MyTestEndpoint",
            };

            var headers = new Dictionary <string, string>
            {
                { "Bar", "34234" },
                { "Foo", "aString1" },
                { "Super", "aString2" }
            };

            var timeout = new TimeoutData
            {
                Time                 = DateTime.UtcNow.AddHours(-1),
                Destination          = new Address("timeouts", RuntimeEnvironment.MachineName),
                SagaId               = Guid.NewGuid(),
                State                = new byte[] { 1, 1, 133, 200 },
                Headers              = headers,
                OwningTimeoutManager = "MyTestEndpoint",
            };

            persister.Add(timeout);

            TimeoutData timeoutData;

            persister.TryRemove(timeout.Id, out timeoutData);

            CollectionAssert.AreEqual(headers, timeoutData.Headers);
        }
        public async Task Remove_WhenNoTimeoutRemoved_ShouldReturnFalse()
        {
            var persister = new TimeoutPersister(store);
            await persister.Add(new TimeoutData(), new ContextBag());

            var result = await persister.TryRemove(Guid.NewGuid().ToString(), new ContextBag());

            Assert.IsFalse(result);
        }
        public async Task Remove_WhenNoTimeoutRemoved_ShouldReturnFalse()
        {
            var persister = new TimeoutPersister(store);
            await persister.Add(new TimeoutData(), new ContextBag());

            var result = await persister.TryRemove(Guid.NewGuid().ToString(), new ContextBag());

            Assert.IsFalse(result);
        }
        public async Task Remove_WhenTimeoutRemoved_ShouldReturnTrue()
        {
            var persister   = new TimeoutPersister(store);
            var timeoutData = new TimeoutData();
            await persister.Add(timeoutData, new ContextBag());

            var result = await persister.TryRemove(timeoutData.Id, new ContextBag());

            Assert.IsTrue(result);
        }
        public async Task Remove_WhenTimeoutRemoved_ShouldReturnTrue()
        {
            var persister = new TimeoutPersister(store);
            var timeoutData = new TimeoutData();
            await persister.Add(timeoutData, new ContextBag());

            var result = await persister.TryRemove(timeoutData.Id, new ContextBag());

            Assert.IsTrue(result);
        }
        public void Should_remove_timeouts_by_id()
        {
            new TimeoutsIndex().Execute(store);

            var persister = new TimeoutPersister
            {
                DocumentStore = store,
                EndpointName  = "MyTestEndpoint",
            };

            var t1 = new TimeoutData
            {
                Time = DateTime.Now.AddYears(-1),
                OwningTimeoutManager = "MyTestEndpoint",
                Headers = new Dictionary <string, string>
                {
                    { "Header1", "Value1" }
                }
            };
            var t2 = new TimeoutData
            {
                Time = DateTime.Now.AddYears(-1),
                OwningTimeoutManager = "MyTestEndpoint",
                Headers = new Dictionary <string, string>
                {
                    { "Header1", "Value1" }
                }
            };

            persister.Add(t1);
            persister.Add(t2);

            WaitForIndexing(store);

            DateTime nextTimeToRunQuery;
            var      timeouts = persister.GetNextChunk(DateTime.UtcNow.AddYears(-3), out nextTimeToRunQuery);

            foreach (var timeout in timeouts)
            {
                TimeoutData timeoutData;
                persister.TryRemove(timeout.Item1, out timeoutData);
            }

            using (var session = store.OpenSession())
            {
                Assert.Null(session.Load <Timeout>(new Guid(t1.Id)));
                Assert.Null(session.Load <Timeout>(new Guid(t2.Id)));
            }
        }
Example #9
0
        public void Never_ever()
        {
            var db = Guid.NewGuid().ToString();

            using (var documentStore = new DocumentStore
            {
                Url = "http://localhost:8081",
                DefaultDatabase = db,
            }.Initialize())
            {
                new TimeoutsIndex().Execute(documentStore);

                var persister = new TimeoutPersister
                {
                    DocumentStore       = documentStore,
                    EndpointName        = "foo",
                    TriggerCleanupEvery = TimeSpan.FromHours(1),             // Make sure cleanup doesn't run automatically
                };

                var startSlice = DateTime.UtcNow.AddYears(-10);
                // avoid cleanup from running during the test by making it register as being run
                Assert.AreEqual(0, persister.GetCleanupChunk(startSlice).Count());

                var expected       = new List <Tuple <string, DateTime> >();
                var lastTimeout    = DateTime.UtcNow;
                var finishedAdding = false;

                new Thread(() =>
                {
                    var sagaId = Guid.NewGuid();
                    for (var i = 0; i < 10000; i++)
                    {
                        var td = new TimeoutData
                        {
                            SagaId               = sagaId,
                            Destination          = new Address("queue", "machine"),
                            Time                 = DateTime.UtcNow.AddSeconds(RandomProvider.GetThreadRandom().Next(1, 20)),
                            OwningTimeoutManager = string.Empty,
                        };
                        persister.Add(td);
                        expected.Add(new Tuple <string, DateTime>(td.Id, td.Time));
                        lastTimeout = (td.Time > lastTimeout) ? td.Time : lastTimeout;
                    }
                    finishedAdding = true;
                    Trace.WriteLine("*** Finished adding ***");
                }).Start();

                // Mimic the behavior of the TimeoutPersister coordinator
                var         found = 0;
                TimeoutData tmptd;
                while (!finishedAdding || startSlice < lastTimeout)
                {
                    DateTime nextRetrieval;
                    var      timeoutDatas = persister.GetNextChunk(startSlice, out nextRetrieval);
                    foreach (var timeoutData in timeoutDatas)
                    {
                        if (startSlice < timeoutData.Item2)
                        {
                            startSlice = timeoutData.Item2;
                        }

                        Assert.IsTrue(persister.TryRemove(timeoutData.Item1, out tmptd));
                        found++;
                    }
                }

                WaitForIndexing(documentStore);

                // If the persister reports stale results have been seen at one point during its normal operation,
                // we need to perform manual cleaup.
                while (true)
                {
                    var chunkToCleanup = persister.GetCleanupChunk(DateTime.UtcNow.AddDays(1)).ToArray();
                    if (chunkToCleanup.Length == 0)
                    {
                        break;
                    }

                    found += chunkToCleanup.Length;
                    foreach (var tuple in chunkToCleanup)
                    {
                        Assert.IsTrue(persister.TryRemove(tuple.Item1, out tmptd));
                    }

                    WaitForIndexing(documentStore);
                }

                using (var session = documentStore.OpenSession())
                {
                    var results = session.Query <TimeoutData>().ToList();
                    Assert.AreEqual(0, results.Count);
                }

                Assert.AreEqual(expected.Count, found);
            }
        }
        public async Task Never_ever()
        {
            var documentStore = store;

            var query = new QueryTimeouts(documentStore, "foo")
            {
                TriggerCleanupEvery = TimeSpan.FromHours(1) // Make sure cleanup doesn't run automatically
            };
            var persister = new TimeoutPersister(documentStore);
            var context   = new ContextBag();

            var startSlice = DateTime.UtcNow.AddYears(-10);

            // avoid cleanup from running during the test by making it register as being run
            Assert.AreEqual(0, (await query.GetCleanupChunk(startSlice)).Count());

            var expected       = new List <Tuple <string, DateTime> >();
            var lastTimeout    = DateTime.UtcNow;
            var finishedAdding = false;

            new Thread(() =>
            {
                var sagaId = Guid.NewGuid();
                for (var i = 0; i < 10000; i++)
                {
                    var td = new TimeoutData
                    {
                        SagaId               = sagaId,
                        Destination          = "queue@machine",
                        Time                 = DateTime.UtcNow.AddSeconds(RandomProvider.GetThreadRandom().Next(1, 20)),
                        OwningTimeoutManager = string.Empty
                    };
                    persister.Add(td, context).Wait();
                    expected.Add(new Tuple <string, DateTime>(td.Id, td.Time));
                    lastTimeout = (td.Time > lastTimeout) ? td.Time : lastTimeout;
                }
                finishedAdding = true;
                Trace.WriteLine("*** Finished adding ***");
            }).Start();

            // Mimic the behavior of the TimeoutPersister coordinator
            var found = 0;

            while (!finishedAdding || startSlice < lastTimeout)
            {
                var timeoutData = await query.GetNextChunk(startSlice);

                foreach (var timeout in timeoutData.DueTimeouts)
                {
                    if (startSlice < timeout.DueTime)
                    {
                        startSlice = timeout.DueTime;
                    }

                    Assert.True(await persister.TryRemove(timeout.Id, context));
                    found++;
                }

                //Todo: Investigate!
                //Without this, sometime it never exited the while loop, even though everything was correctly removed
                if (!timeoutData.DueTimeouts.Any())
                {
                    startSlice = timeoutData.NextTimeToQuery;
                }
            }


            // If the persister reports stale results have been seen at one point during its normal operation,
            // we need to perform manual cleaup.
            while (true)
            {
                var chunkToCleanup = (await query.GetCleanupChunk(DateTime.UtcNow.AddDays(1))).ToArray();
                if (chunkToCleanup.Length == 0)
                {
                    break;
                }

                found += chunkToCleanup.Length;
                foreach (var tuple in chunkToCleanup)
                {
                    Assert.True(await persister.TryRemove(tuple.Id, context));
                }
            }

            using (var session = documentStore.OpenSession())
            {
                var results = session.Query <TimeoutDocument>().ToList();
                Assert.AreEqual(0, results.Count);
            }

            Assert.AreEqual(expected.Count, found);
        }
        public async Task Should_not_skip_timeouts_also_with_multiple_clients_adding_timeouts()
        {
            var documentStore = store;

            var query = new QueryTimeouts(documentStore, "foo")
            {
                TriggerCleanupEvery = TimeSpan.FromDays(1) // Make sure cleanup doesn't run automatically
            };
            var persister = new TimeoutPersister(documentStore);
            var context   = new ContextBag();

            var startSlice = DateTime.UtcNow.AddYears(-10);

            // avoid cleanup from running during the test by making it register as being run
            Assert.AreEqual(0, (await query.GetCleanupChunk(startSlice)).Count());

            const int insertsPerThread    = 1000;
            var       expected            = 0;
            var       lastExpectedTimeout = DateTime.UtcNow;
            var       finishedAdding1     = false;
            var       finishedAdding2     = false;

            new Thread(() =>
            {
                var sagaId = Guid.NewGuid();
                for (var i = 0; i < insertsPerThread; i++)
                {
                    var td = new TimeoutData
                    {
                        SagaId               = sagaId,
                        Destination          = "queue@machine",
                        Time                 = DateTime.UtcNow.AddSeconds(RandomProvider.GetThreadRandom().Next(1, 20)),
                        OwningTimeoutManager = string.Empty
                    };
                    persister.Add(td, context).Wait();
                    Interlocked.Increment(ref expected);
                    lastExpectedTimeout = (td.Time > lastExpectedTimeout) ? td.Time : lastExpectedTimeout;
                }
                finishedAdding1 = true;
                Console.WriteLine("*** Finished adding ***");
            }).Start();

            new Thread(() =>
            {
                var persister2 = new TimeoutPersister(store);

                var sagaId = Guid.NewGuid();
                for (var i = 0; i < insertsPerThread; i++)
                {
                    var td = new TimeoutData
                    {
                        SagaId               = sagaId,
                        Destination          = "queue@machine",
                        Time                 = DateTime.UtcNow.AddSeconds(RandomProvider.GetThreadRandom().Next(1, 20)),
                        OwningTimeoutManager = string.Empty
                    };
                    persister2.Add(td, context).Wait();
                    Interlocked.Increment(ref expected);
                    lastExpectedTimeout = (td.Time > lastExpectedTimeout) ? td.Time : lastExpectedTimeout;
                }

                finishedAdding2 = true;
                Console.WriteLine("*** Finished adding via a second client connection ***");
            }).Start();

            // Mimic the behavior of the TimeoutPersister coordinator
            var found = 0;

            while (!finishedAdding1 || !finishedAdding2 || startSlice < lastExpectedTimeout)
            {
                var timeoutDatas = await query.GetNextChunk(startSlice);

                foreach (var timeoutData in timeoutDatas.DueTimeouts)
                {
                    if (startSlice < timeoutData.DueTime)
                    {
                        startSlice = timeoutData.DueTime;
                    }

                    Assert.True(await persister.TryRemove(timeoutData.Id, context));
                    found++;
                }
            }

            // If the persister reports stale results have been seen at one point during its normal operation,
            // we need to perform manual cleaup.
            while (true)
            {
                var chunkToCleanup = (await query.GetCleanupChunk(DateTime.UtcNow.AddDays(1))).ToArray();
                Console.WriteLine("Cleanup: got a chunk of size " + chunkToCleanup.Length);
                if (chunkToCleanup.Length == 0)
                {
                    break;
                }

                found += chunkToCleanup.Length;
                foreach (var tuple in chunkToCleanup)
                {
                    Assert.True(await persister.TryRemove(tuple.Id, context));
                }
            }

            using (var session = documentStore.OpenSession())
            {
                var results = session.Query <TimeoutDocument>().ToList();
                Assert.AreEqual(0, results.Count);
            }

            Assert.AreEqual(expected, found);
        }
        public async Task Never_ever()
        {
            var db = Guid.NewGuid().ToString();
            using (var documentStore = new DocumentStore
            {
                Url = "http://*****:*****@machine",
                            Time = DateTime.UtcNow.AddSeconds(RandomProvider.GetThreadRandom().Next(1, 20)),
                            OwningTimeoutManager = string.Empty
                        };
                        persister.Add(td, context).Wait();
                        expected.Add(new Tuple<string, DateTime>(td.Id, td.Time));
                        lastTimeout = (td.Time > lastTimeout) ? td.Time : lastTimeout;
                    }
                    finishedAdding = true;
                    Trace.WriteLine("*** Finished adding ***");
                }).Start();

                // Mimic the behavior of the TimeoutPersister coordinator
                var found = 0;
                while (!finishedAdding || startSlice < lastTimeout)
                {
                    var timeoutData = await query.GetNextChunk(startSlice);
                    foreach (var timeout in timeoutData.DueTimeouts)
                    {
                        if (startSlice < timeout.DueTime)
                        {
                            startSlice = timeout.DueTime;
                        }

                        Assert.True(await persister.TryRemove(timeout.Id, context));
                        found++;
                    }
                }

                WaitForIndexing(documentStore);

                // If the persister reports stale results have been seen at one point during its normal operation,
                // we need to perform manual cleaup.
                while (true)
                {
                    var chunkToCleanup = (await query.GetCleanupChunk(DateTime.UtcNow.AddDays(1))).ToArray();
                    if (chunkToCleanup.Length == 0)
                    {
                        break;
                    }

                    found += chunkToCleanup.Length;
                    foreach (var tuple in chunkToCleanup)
                    {
                        Assert.True(await persister.TryRemove(tuple.Id, context));
                    }

                    WaitForIndexing(documentStore);
                }

                using (var session = documentStore.OpenAsyncSession())
                {
                    var results = await session.Query<TimeoutData>().ToListAsync();
                    Assert.AreEqual(0, results.Count);
                }

                Assert.AreEqual(expected.Count, found);
            }
        }