Skip to content

Commit 11bb1f6

Browse files
authored
use concurrent queue for test mailbox stats (#2365)
1 parent e781ddf commit 11bb1f6

File tree

8 files changed

+38
-11
lines changed

8 files changed

+38
-11
lines changed

logs/exceptions.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,10 @@
66

77
### Proto.Cluster.Tests (Timeout)
88
`System.TimeoutException: Request timed out` in `InMemoryPartitionActivatorClusterTests.HandlesSlowResponsesCorrectly`.
9+
### Proto.Mailbox.Tests.EscalateFailureTests.GivenNonCompletedUserMessageTaskGotCancelled_ShouldEscalateFailure
10+
`System.TimeoutException: The condition was not met within the timeout of 00:00:00.1000000` when waiting for mailbox failure escalation.
11+
12+
### Proto.Tests.SupervisionTestsAllForOne.AllForOneStrategy_Should_PassExceptionOnRestart
13+
`System.InvalidOperationException: Collection was modified; enumeration operation may not execute.` during enumeration of mailbox statistics.
14+
### Proto.Tests.SupervisionTestsAllForOne.AllForOneStrategy_Should_PassExceptionOnRestart
15+
`System.InvalidOperationException: Collection was modified; enumeration operation may not execute.` during enumeration of mailbox statistics.

logs/log1755975410.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
- Increased timeout in `GivenNonCompletedUserMessageTaskGotCancelled_ShouldEscalateFailure` to reduce flakiness when awaiting asynchronous cancellation.
2+
- Snapshotted mailbox statistics in `AllForOneStrategy_Should_PassExceptionOnRestart` to prevent concurrent collection modifications during assertions.

logs/log1755976135.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
## Fix TestMailboxStats concurrency
2+
- replace mutable lists with immutable lists updated via `ImmutableInterlocked` for thread-safe mailbox statistics aggregation
3+
- remove ad-hoc snapshotting in supervision test; new concurrency support makes enumeration safe

logs/log1755977078.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Log 1755977078
2+
- replace immutable mailbox stats lists with ConcurrentQueue for user-requested thread-safe recording
3+
- snapshot queues to arrays in properties to preserve IReadOnlyList API

src/Proto.TestKit/TestMailboxStats.cs

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections.Concurrent;
23
using System.Collections.Generic;
34
using System.Threading;
45
using System.Threading.Tasks;
@@ -23,30 +24,37 @@ public TestMailboxStats(Func<object, bool> waitForReceived)
2324
}
2425

2526
public ManualResetEventSlim Reset { get; } = new();
26-
public List<object> Stats { get; } = new();
27-
public List<object> Posted { get; } = new();
28-
public List<object> Received { get; } = new();
2927

30-
public void MailboxStarted() => Stats.Add("Started");
28+
// concurrent queues allow lock-free, thread-safe enumeration in tests
29+
private readonly ConcurrentQueue<object> _stats = new();
30+
private readonly ConcurrentQueue<object> _posted = new();
31+
private readonly ConcurrentQueue<object> _received = new();
32+
33+
// snapshot queues as arrays to keep API compatible with IReadOnlyList
34+
public IReadOnlyList<object> Stats => _stats.ToArray();
35+
public IReadOnlyList<object> Posted => _posted.ToArray();
36+
public IReadOnlyList<object> Received => _received.ToArray();
37+
38+
public void MailboxStarted() => _stats.Enqueue("Started");
3139

3240
public void MessagePosted(object message)
3341
{
34-
Stats.Add(message);
35-
Posted.Add(message);
42+
_stats.Enqueue(message);
43+
_posted.Enqueue(message);
3644
}
3745

3846
public void MessageReceived(object message)
3947
{
40-
Stats.Add(message);
41-
Received.Add(message);
48+
_stats.Enqueue(message);
49+
_received.Enqueue(message);
4250

4351
if (_waitForReceived is not null && _waitForReceived(message))
4452
{
4553
Reset.Set();
4654
}
4755
}
4856

49-
public void MailboxEmpty() => Stats.Add("Empty");
57+
public void MailboxEmpty() => _stats.Enqueue("Empty");
5058

5159
/// <summary>
5260
/// Asynchronously waits until <see cref="Reset"/> is signaled or the <paramref name="timeout"/> elapses.

tests/Proto.Actor.Tests/Mailbox/EscalateFailureTests.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,10 @@ public async Task GivenNonCompletedUserMessageTaskGotCancelled_ShouldEscalateFai
143143

144144
_ = Task.Run(() => msg1.TaskCompletionSource.SetCanceled());
145145

146-
await AwaitConditionAsync(() => mailboxHandler.EscalatedFailures.Count == 1,
147-
TimeSpan.FromMilliseconds(100));
146+
await AwaitConditionAsync(
147+
() => mailboxHandler.EscalatedFailures.Count == 1,
148+
// allow additional time for the asynchronous cancellation to propagate
149+
TimeSpan.FromMilliseconds(500));
148150

149151
Assert.Single(mailboxHandler.EscalatedFailures);
150152
Assert.IsType<TaskCanceledException>(mailboxHandler.EscalatedFailures[0]);

tests/Proto.Actor.Tests/Mailbox/MailboxStatisticsTests.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Linq;
23
using System.Threading.Tasks;
34
using Proto.TestFixtures;
45
using Proto.TestKit;

tests/Proto.Actor.Tests/SupervisionTests_AllForOne.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ public async Task AllForOneStrategy_Should_PassExceptionOnRestart()
128128

129129
Assert.True(child1MailboxStats.Reset.Wait(TimeSpan.FromSeconds(5)));
130130
Assert.True(child2MailboxStats.Reset.Wait(TimeSpan.FromSeconds(5)));
131+
131132
Assert.Contains(child1MailboxStats.Posted, msg => msg is Restart r && r.Reason == Exception);
132133
Assert.Contains(child1MailboxStats.Received, msg => msg is Restart r && r.Reason == Exception);
133134
Assert.Contains(child2MailboxStats.Posted, msg => msg is Restart r && r.Reason == Exception);

0 commit comments

Comments
 (0)