Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,46 @@ public void WriteTo(ITestOutputHelper log)
}
}

public async Task WaitForLogsAsync(int[] expectedErrorIds, TimeSpan timeout)
{
var deadline = DateTime.UtcNow + timeout;
while (DateTime.UtcNow < deadline)
{
lock (_items)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if it would be enough to just wait until this could be acquired once? Or are the items added asynchronously acquiring the lock potentially after this is called?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logging itself is synchronous (line 120 adds to _items under lock), but it's called from the catch block (line 380 in DefaultHybridCache.StampedeStateT.cs) that executes asynchronously in the background task.

l2.LastWrite tracks when the write task completes, but doesn't guarantee the catch block has finished executing. The catch block could still be running after LastWrite is done, especially with thread scheduling variations.

So we need to poll: we're waiting for the logger to be called (which happens async), not just for the lock to be available. Acquiring the lock once would be a snapshot at a single point in time - we might check before the background catch block calls the logger.

{
// Check for exact match to avoid race conditions with AssertErrors
if (_items.Count == expectedErrorIds.Length)
{
bool match = true;
for (int i = 0; i < expectedErrorIds.Length; i++)
{
if (_items[i].eventId.Id != expectedErrorIds[i])
{
match = false;
break;
}
}

if (match)
{
return; // Success
}
}

// If we have more logs than expected, something unexpected happened
// Stop waiting to let AssertErrors report the mismatch
if (_items.Count > expectedErrorIds.Length)
{
return;
}
}

await Task.Delay(10);
}

// Timeout reached, will fail in AssertErrors
}

public void AssertErrors(int[] errorIds)
{
lock (_items)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ public async Task WriteFailureInvisible(BreakType writeBreak, params int[] error
}

await l2.LastWrite; // allows out-of-band write to complete
await Task.Delay(150); // even then: thread jitter can cause problems

// Wait for logs to be written (with timeout to avoid hanging on failure)
await log.WaitForLogsAsync(errorIds, TimeSpan.FromSeconds(5));

log.WriteTo(testLog);
log.AssertErrors(errorIds);
Expand Down
Loading