feat(siteruntime): WaitForAsync/WaitResult + quality-gated WaitAsync (spec §3, §4.2)
This commit is contained in:
@@ -577,10 +577,22 @@ public class InstanceActor : ReceiveActor
|
||||
// and return WITHOUT registering (no timeout scheduled).
|
||||
if (_attributes.TryGetValue(req.AttributeName, out var current))
|
||||
{
|
||||
// Effective quality used for BOTH the §4.2 quality gate and the match
|
||||
// reply — the same `?? "Good"` default the reply has always used.
|
||||
_attributeQualities.TryGetValue(req.AttributeName, out var fastQuality);
|
||||
var effectiveQuality = fastQuality ?? "Good";
|
||||
|
||||
bool fastMatch;
|
||||
try
|
||||
{
|
||||
fastMatch = test(current);
|
||||
// §4.2 quality gate ANDed with the value test, both INSIDE the guard:
|
||||
// in quality-gated mode a value already at target but at Bad/Uncertain
|
||||
// quality is NOT a fast match — it falls through to register + schedule
|
||||
// the timeout like any other pending waiter (do NOT fast-reply matched).
|
||||
fastMatch =
|
||||
(!req.RequireGoodQuality
|
||||
|| string.Equals(effectiveQuality, "Good", StringComparison.Ordinal))
|
||||
&& test(current);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -595,9 +607,8 @@ public class InstanceActor : ReceiveActor
|
||||
|
||||
if (fastMatch)
|
||||
{
|
||||
_attributeQualities.TryGetValue(req.AttributeName, out var quality);
|
||||
replyer.Tell(new WaitForAttributeResponse(
|
||||
req.CorrelationId, Matched: true, current, quality ?? "Good", TimedOut: false));
|
||||
req.CorrelationId, Matched: true, current, effectiveQuality, TimedOut: false));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -617,7 +628,7 @@ public class InstanceActor : ReceiveActor
|
||||
req.Timeout, Self, new WaitForAttributeTimeout(req.CorrelationId), Self);
|
||||
|
||||
_attributeWaiters[req.CorrelationId] =
|
||||
new PendingWait(req.AttributeName, test, replyer, handle);
|
||||
new PendingWait(req.AttributeName, test, replyer, handle, req.RequireGoodQuality);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1101,7 +1112,14 @@ public class InstanceActor : ReceiveActor
|
||||
bool matched;
|
||||
try
|
||||
{
|
||||
matched = pending.Test(changed.Value);
|
||||
// §4.2 quality gate ANDed with the value test, both INSIDE the guard:
|
||||
// in quality-gated mode a value reaching the target at Bad/Uncertain
|
||||
// quality is NOT a match — the waiter stays pending until it satisfies
|
||||
// the test at Good quality (or times out).
|
||||
matched =
|
||||
(!pending.RequireGoodQuality
|
||||
|| string.Equals(changed.Quality, "Good", StringComparison.Ordinal))
|
||||
&& pending.Test(changed.Value);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -1410,9 +1428,15 @@ public class InstanceActor : ReceiveActor
|
||||
/// <param name="Test">The match test (decoded-target equality OR site-local predicate OR any-change).</param>
|
||||
/// <param name="Replyer">The original sender to reply to on match / timeout.</param>
|
||||
/// <param name="Timeout">The scheduled timeout handle, canceled on match.</param>
|
||||
/// <param name="RequireGoodQuality">
|
||||
/// Quality-gated ("Good"-only) mode (spec §4.2): when <c>true</c>, the resolve
|
||||
/// loop additionally requires <c>changed.Quality == "Good"</c> before the test
|
||||
/// can match.
|
||||
/// </param>
|
||||
private sealed record PendingWait(
|
||||
string AttributeName,
|
||||
Func<object?, bool> Test,
|
||||
IActorRef Replyer,
|
||||
ICancelable Timeout);
|
||||
ICancelable Timeout,
|
||||
bool RequireGoodQuality);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user