-
Notifications
You must be signed in to change notification settings - Fork 1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Alternative implementation of AtomicState
leveraging WaitAsync
#6109
Alternative implementation of AtomicState
leveraging WaitAsync
#6109
Conversation
NOTE: for whatever reason, |
BTW, some of the CB's tests are failing now because they seem tweaked to work with the current CB implementation. If this PR goes ahead, I'll make sure to fix them all. |
got it - thanks for letting us know! |
Does #6108 need to be merged first or does this? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM - please proceed
e74696f
to
61885c4
Compare
No, I've included the |
9dcef85
to
c22486f
Compare
For public void WithSyncCircuitBreaker(Action body) =>
WithCircuitBreaker(body, b => Task.Run(b)).GetAwaiter().GetResult(); |
bf42423
to
bda4de1
Compare
LMK when this is ready for review |
I think that's fine IMHO |
bda4de1
to
d97fc2f
Compare
@Aaronontheweb this is ready for review. I have an improved version of the |
Looks like you have a test suite issue here:
|
8b69365
to
29c012a
Compare
05fed9a
to
d9a288f
Compare
Going to re-review this this week |
I haven't had the time to work on this some more, and I'm still not sure why that test keeps failing. I even went ahead and reimplemented |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I have your failing test figured out
@@ -293,10 +293,59 @@ protected static async Task<bool> InternalAwaitConditionAsync(Func<Task<bool>> c | |||
return true; | |||
} | |||
|
|||
private static void ConditionalLog(ILoggingAdapter logger, string format, params object[] args) | |||
protected void AwaitCond(Func<bool> p, TimeSpan? max = null, TimeSpan? interval = null, string message = "") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't we already have an AwaitCondition
method or does this do something different?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The behavior of AwaitCondition
is different from the JVM, that's why I tried a straight port instead. No luck, keeps failing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AwaitCondition
arbitrarily calculates the interval
(when not specified) as a 10th of max
. It should be a fixed 100 ms
, otherwise tests ported from the JVM might not behave as expected.
{ | ||
[Fact(DisplayName = "A synchronous circuit breaker that is half open should pass call and transition to close on success")] | ||
public void Should_Pass_Call_And_Transition_To_Close_On_Success( ) | ||
[Fact(DisplayName = "A synchronous circuit breaker that is closed must increment failure count on callTimeout before call finishes")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So this spec is currently racy
var breaker = ShortCallTimeoutCb(); | ||
Task.Run(() => breaker.Instance.WithSyncCircuitBreaker(() => Thread.Sleep(Dilated(TimeSpan.FromSeconds(1))))); | ||
Within(TimeSpan.FromMilliseconds(900), | ||
() => AwaitCond(() => breaker.Instance.CurrentFailureCount == 1, Dilated(TimeSpan.FromMilliseconds(100)))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think your problem here is your parameters on AwaitCond
- you meant to set Dilated(TimeSpan.FromMilliseconds(100))
as the interval but it's being used as the max value here. @ismaelhamed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Aaronontheweb , see my comment above. In the meantime, I've fixed it by passing both max
and interval
.
96d228b
to
d8545d0
Compare
052c442
to
ffe4c43
Compare
@ismaelhamed is this ready for review? |
The implementation yes, but I couldn't figure out where the problem with the specs was. I'll give it another shot soon. |
867be27
to
30a69af
Compare
Unrelated test failing now. |
30a69af
to
93ac7e8
Compare
@ismaelhamed is this good for me to review again? |
ah yes, it is - you just requested one from me! I'll get right on it. |
93ac7e8
to
dc45d73
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Queued for auto-merge - nice work @ismaelhamed |
fd41320
to
8b793ed
Compare
8b793ed
to
3f1490c
Compare
Might be related to #6106
The circuit breaker, in its current implementation, could give false positives (signal tasks as done when in reality they failed).
I ported the
CircuitBreakerStressSpec
and slightly modified it to make all tasks take longer than the CB'sCallTimeout
, so that all of them fail. Instead, by running the test you can see that they are all "marked" as succeeded (DoneCount
).Upon further inspection:
The tasks indeed all failed with a
TimeException
, but the exception is swallowed by theCallFail
method. This makes impossible to capture theTimeException
outside the CB --as demonstrated by theStressActor
.Because we are awaiting the task first, and only after it finishes we check whether it took longer than the
CallTimeout
, we could potentially be awaiting indefinitely for the task to complete. This PR leverages the newTask.WaitAsync
in .NET6 instead.When compared with the results of the test in the previous PR, we now get the correct behavior:
BEFORE
AFTER