Skip to content

Commit 563a5ad

Browse files
committed
Change how exceptions are handled to better relate them to individual items
1 parent 81fc6e4 commit 563a5ad

File tree

4 files changed

+42
-11
lines changed

4 files changed

+42
-11
lines changed

osu.Server.QueueProcessor.Tests/BatchProcessorTests.cs

+1
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ public void MultipleErrorsAttachedToCorrectItems()
209209
processor.Error += (exception, item) =>
210210
{
211211
Assert.NotNull(exception);
212+
Assert.Equal(exception, item.Exception);
212213

213214
gotCorrectExceptionForItem1 |= Equals(item.Data, obj1.Data) && exception.Message == "1";
214215
gotCorrectExceptionForItem2 |= Equals(item.Data, obj2.Data) && exception.Message == "2";

osu.Server.QueueProcessor.Tests/TestBatchProcessor.cs

+8-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,14 @@ protected override void ProcessResults(IEnumerable<FakeData> items)
2121
{
2222
foreach (var item in items)
2323
{
24-
Received?.Invoke(item);
24+
try
25+
{
26+
Received?.Invoke(item);
27+
}
28+
catch (Exception e)
29+
{
30+
item.Exception = e;
31+
}
2532
}
2633
}
2734

osu.Server.QueueProcessor/QueueItem.cs

+11-1
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,21 @@ namespace osu.Server.QueueProcessor
1212
[Serializable]
1313
public abstract class QueueItem
1414
{
15+
[IgnoreDataMember]
16+
private bool failed;
17+
1518
/// <summary>
1619
/// Set to <c>true</c> to mark this item is failed. This will cause it to be retried.
1720
/// </summary>
1821
[IgnoreDataMember]
19-
public bool Failed { get; set; }
22+
public bool Failed
23+
{
24+
get => failed || Exception != null;
25+
set => failed = value;
26+
}
27+
28+
[IgnoreDataMember]
29+
public Exception? Exception { get; set; }
2030

2131
/// <summary>
2232
/// The number of times processing this item has been retried. Handled internally by <see cref="QueueProcessor{T}"/>.

osu.Server.QueueProcessor/QueueProcessor.cs

+22-9
Original file line numberDiff line numberDiff line change
@@ -132,11 +132,11 @@ public void Run(CancellationToken cancellation = default)
132132

133133
// individual processing should not be cancelled as we have already grabbed from the queue.
134134
Task.Factory.StartNew(() => { ProcessResults(items); }, CancellationToken.None, TaskCreationOptions.HideScheduler, threadPool)
135-
.ContinueWith(t =>
135+
.ContinueWith(_ =>
136136
{
137137
foreach (var item in items)
138138
{
139-
if (t.Exception != null || item.Failed)
139+
if (item.Failed)
140140
{
141141
Interlocked.Increment(ref totalErrors);
142142

@@ -145,12 +145,12 @@ public void Run(CancellationToken cancellation = default)
145145

146146
Interlocked.Increment(ref consecutiveErrors);
147147

148-
Error?.Invoke(t.Exception, item);
148+
Error?.Invoke(item.Exception, item);
149149

150-
if (t.Exception != null)
151-
SentrySdk.CaptureException(t.Exception);
150+
if (item.Exception != null)
151+
SentrySdk.CaptureException(item.Exception);
152152

153-
Console.WriteLine($"Error processing {item}: {t.Exception}");
153+
Console.WriteLine($"Error processing {item}: {item.Exception}");
154154
attemptRetry(item);
155155
}
156156
else
@@ -197,8 +197,6 @@ private void setupSentry(SentryOptions options)
197197

198198
private void attemptRetry(T item)
199199
{
200-
item.Failed = false;
201-
202200
if (item.TotalRetries++ < config.MaxRetries)
203201
{
204202
Console.WriteLine($"Re-queueing for attempt {item.TotalRetries} / {config.MaxRetries}");
@@ -274,11 +272,26 @@ protected virtual void ProcessResult(T item)
274272
/// <summary>
275273
/// Implement to process batches of items from the queue.
276274
/// </summary>
275+
/// <remarks>
276+
/// In most cases, you should only need to override and implement <see cref="ProcessResult"/>.
277+
/// Only override this if you need more efficient batch processing.
278+
///
279+
/// If overriding this method, you should try-catch for exceptions, and set any exception against
280+
/// the relevant <see cref="QueueItem"/>. If this is not done, failures will not be handled correctly.</remarks>
277281
/// <param name="items">The items to process.</param>
278282
protected virtual void ProcessResults(IEnumerable<T> items)
279283
{
280284
foreach (var item in items)
281-
ProcessResult(item);
285+
{
286+
try
287+
{
288+
ProcessResult(item);
289+
}
290+
catch (Exception e)
291+
{
292+
item.Exception = e;
293+
}
294+
}
282295
}
283296
}
284297
}

0 commit comments

Comments
 (0)