Skip to content

Commit 29cc04d

Browse files
author
John Simons
committed
Merge branch 'hotfix-3.3.9' into support-3.3
2 parents 0ea5c06 + 6349782 commit 29cc04d

File tree

4 files changed

+351
-42
lines changed

4 files changed

+351
-42
lines changed

src/timeout/NServiceBus.Timeout.Hosting.Windows/Persistence/RavenTimeoutPersistence.cs

+71-38
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ public class RavenTimeoutPersistence : IPersistTimeouts
1414
{
1515
readonly IDocumentStore store;
1616

17+
public TimeSpan CleanupGapFromTimeslice { get; set; }
18+
public TimeSpan TriggerCleanupEvery { get; set; }
19+
DateTime lastCleanupTime = DateTime.MinValue;
20+
1721
public RavenTimeoutPersistence(IDocumentStore store)
1822
{
1923
this.store = store;
@@ -42,36 +46,72 @@ public RavenTimeoutPersistence(IDocumentStore store)
4246
Map = docs => from doc in docs
4347
select new { doc.SagaId }
4448
}, true);
45-
49+
50+
TriggerCleanupEvery = TimeSpan.FromMinutes(2);
51+
CleanupGapFromTimeslice = TimeSpan.FromMinutes(1);
52+
}
53+
54+
private static IRavenQueryable<TimeoutData> GetChunkQuery(IDocumentSession session)
55+
{
56+
session.Advanced.AllowNonAuthoritativeInformation = true;
57+
return session.Query<TimeoutData>("RavenTimeoutPersistence/TimeoutDataSortedByTime")
58+
.OrderBy(t => t.Time)
59+
.Where(t =>
60+
t.OwningTimeoutManager == String.Empty ||
61+
t.OwningTimeoutManager == Configure.EndpointName);
62+
}
63+
64+
public IEnumerable<Tuple<string, DateTime>> GetCleanupChunk(DateTime startSlice)
65+
{
66+
using (var session = OpenSession())
67+
{
68+
var chunk = GetChunkQuery(session)
69+
.Where(t => t.Time <= startSlice.Subtract(CleanupGapFromTimeslice))
70+
.Select(t => new
71+
{
72+
t.Id,
73+
t.Time
74+
})
75+
.Take(1024)
76+
.ToList()
77+
.Select(arg => new Tuple<string, DateTime>(arg.Id, arg.Time));
78+
79+
lastCleanupTime = DateTime.UtcNow;
80+
81+
return chunk;
82+
}
4683
}
4784

4885
public List<Tuple<string, DateTime>> GetNextChunk(DateTime startSlice, out DateTime nextTimeToRunQuery)
4986
{
5087
try
5188
{
5289
var now = DateTime.UtcNow;
53-
var skip = 0;
5490
var results = new List<Tuple<string, DateTime>>();
91+
92+
// Allow for occasionally cleaning up old timeouts for edge cases where timeouts have been
93+
// added after startSlice have been set to a later timout and we might have missed them
94+
// because of stale indexes.
95+
if (lastCleanupTime.Add(TriggerCleanupEvery) > now || lastCleanupTime == DateTime.MinValue)
96+
{
97+
results.AddRange(GetCleanupChunk(startSlice));
98+
}
99+
100+
var skip = 0;
55101
var numberOfRequestsExecutedSoFar = 0;
56102
RavenQueryStatistics stats;
57-
58103
do
59104
{
60105
using (var session = OpenSession())
61106
{
62107
session.Advanced.AllowNonAuthoritativeInformation = true;
63108

64-
var query = session.Query<TimeoutData>("RavenTimeoutPersistence/TimeoutDataSortedByTime")
65-
.Where(
66-
t =>
67-
t.OwningTimeoutManager == String.Empty ||
68-
t.OwningTimeoutManager == Configure.EndpointName)
69-
.Where(
70-
t =>
71-
t.Time > startSlice &&
72-
t.Time <= now)
73-
.OrderBy(t => t.Time)
74-
.Select(t => new {t.Id, t.Time})
109+
var query = GetChunkQuery(session)
110+
.Where(
111+
t =>
112+
t.Time > startSlice &&
113+
t.Time <= now)
114+
.Select(t => new { t.Id, t.Time })
75115
.Statistics(out stats);
76116
do
77117
{
@@ -87,33 +127,29 @@ public List<Tuple<string, DateTime>> GetNextChunk(DateTime startSlice, out DateT
87127
}
88128
} while (skip < stats.TotalResults);
89129

90-
using (var session = OpenSession())
130+
// Set next execution to be now if we received stale results.
131+
// Delay the next execution a bit if we results weren't stale and we got the full chunk.
132+
if (stats.IsStale)
133+
{
134+
nextTimeToRunQuery = now;
135+
}
136+
else
91137
{
92-
session.Advanced.AllowNonAuthoritativeInformation = true;
93-
94-
//Retrieve next time we need to run query
95-
var startOfNextChunk =
96-
session.Query<TimeoutData>("RavenTimeoutPersistence/TimeoutDataSortedByTime")
97-
.Where(
98-
t =>
99-
t.OwningTimeoutManager == String.Empty ||
100-
t.OwningTimeoutManager == Configure.EndpointName)
138+
using (var session = OpenSession())
139+
{
140+
var beginningOfNextChunk = GetChunkQuery(session)
101141
.Where(t => t.Time > now)
102-
.OrderBy(t => t.Time)
103-
.Select(t => new {t.Id, t.Time})
142+
.Take(1)
143+
.Select(t => t.Time)
104144
.FirstOrDefault();
105145

106-
if (startOfNextChunk != null)
107-
{
108-
nextTimeToRunQuery = startOfNextChunk.Time;
109-
}
110-
else
111-
{
112-
nextTimeToRunQuery = DateTime.UtcNow.AddMinutes(10);
146+
nextTimeToRunQuery = (beginningOfNextChunk == default(DateTime))
147+
? DateTime.UtcNow.AddMinutes(10)
148+
: beginningOfNextChunk.ToUniversalTime();
113149
}
114-
115-
return results;
116150
}
151+
152+
return results;
117153
}
118154
catch (Exception)
119155
{
@@ -151,9 +187,6 @@ public bool TryRemove(string timeoutId, out TimeoutData timeoutData)
151187
if (timeoutData == null)
152188
return false;
153189

154-
timeoutData.Time = DateTime.UtcNow.AddYears(-1);
155-
session.SaveChanges();
156-
157190
session.Delete(timeoutData);
158191
session.SaveChanges();
159192

tests/timeout/NServiceBus.Timeout.Tests/NServiceBus.Timeout.Tests.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@
108108
<Reference Include="Microsoft.CSharp" />
109109
</ItemGroup>
110110
<ItemGroup>
111+
<Compile Include="RavenTimeoutPersisterTests.cs" />
111112
<Compile Include="When_receiving_timeouts.cs" />
112113
<Compile Include="When_pooling_timeouts.cs" />
113114
<Compile Include="FakeMessageSender.cs" />

0 commit comments

Comments
 (0)