-
Notifications
You must be signed in to change notification settings - Fork 43
feat: add means of awaiting event emission, fix flaky build #1463
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
feat: add means of awaiting event emission, fix flaky build #1463
Conversation
Signed-off-by: christian.lutnik <[email protected]>
final TriConsumer<EventProvider, ProviderEvent, ProviderEventDetails> localOnEmit = this.onEmit; | ||
if (localOnEmit != null) { | ||
emitterExecutor.submit(() -> localOnEmit.accept(this, event, details)); | ||
try (var ignored = OpenFeatureAPI.lock.readLockAutoCloseable()) { |
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.
It's not nice to access the static lock that's clearly only exposed for testing, but we need to use this very lock to protect against concurrent reads/writes to the underlying map.
I removed the call to the emitterExecutor
, so now all listeners are invoked sequentially on the calling thread. This was needed as several tests expect the state of the provider to be set immediately after calling this method.
If we consider this a problem, I could work around this issue by returning something our tests can wait for. In this case, we would need to call both the localOnEmit
and the localEventProviderListener
in the emitterExecutor
.
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.
By moving the call from the emitterExecutor
to the current thread, I reintroduced a race condition that was already fixed.
Therefore I added the executor again. This means that some tests will fail that expect the state of the provider to be updated immediately after a call to emit
. This is why I now return an Awaitable
, for which those tests (or users) can wait.
Signed-off-by: christian.lutnik <[email protected]>
@@ -21,7 +21,6 @@ | |||
@Slf4j | |||
public abstract class EventProvider implements FeatureProvider { | |||
private EventProviderListener eventProviderListener; | |||
private final ExecutorService emitterExecutor = Executors.newCachedThreadPool(); |
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.
Not needed anymore
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.
Wrong, we do need it
Signed-off-by: christian.lutnik <[email protected]>
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.
Thank you! I really would love to have the same detail and knowledge as you have for concurrency. Thank you!
Signed-off-by: christian.lutnik <[email protected]>
Signed-off-by: christian.lutnik <[email protected]>
Signed-off-by: christian.lutnik <[email protected]>
Signed-off-by: christian.lutnik <[email protected]>
Signed-off-by: christian.lutnik <[email protected]>
Signed-off-by: christian.lutnik <[email protected]>
Signed-off-by: christian.lutnik <[email protected]>
Signed-off-by: christian.lutnik <[email protected]>
Signed-off-by: christian.lutnik <[email protected]>
Signed-off-by: christian.lutnik <[email protected]>
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #1463 +/- ##
============================================
+ Coverage 92.88% 93.40% +0.51%
- Complexity 483 490 +7
============================================
Files 45 46 +1
Lines 1167 1182 +15
Branches 101 103 +2
============================================
+ Hits 1084 1104 +20
+ Misses 53 48 -5
Partials 30 30
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
@toddbaert in theory, this is a breaking change. The state of the provider is not set synchronously when calling the |
/** | ||
* A class to help with synchronization. | ||
*/ | ||
public class Awaitable { |
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 like this.
handlerMap.put(ProviderEvent.PROVIDER_CONFIGURATION_CHANGED, new ArrayList<>()); | ||
handlerMap.put(ProviderEvent.PROVIDER_ERROR, new ArrayList<>()); | ||
handlerMap.put(ProviderEvent.PROVIDER_STALE, new ArrayList<>()); | ||
handlerMap.put(ProviderEvent.PROVIDER_READY, new ConcurrentLinkedQueue<>()); |
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.
Good idea.
@@ -93,8 +110,8 @@ public void emit(ProviderEvent event, ProviderEventDetails details) { | |||
* | |||
* @param details The details of the event | |||
*/ | |||
public void emitProviderReady(ProviderEventDetails details) { | |||
emit(ProviderEvent.PROVIDER_READY, details); | |||
public Awaitable emitProviderReady(ProviderEventDetails details) { |
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.
This is a public class people can override to implement a provider that supports events. I like this API and I think it's handy to have.
I was trying to see if there was any way this could be considered breaking. I tried adding this at the top of the class:
private BiConsumer<ProviderEvent, ProviderEventDetails> doesThisCompile = this::emit;
And (surprisingly to me) before and after your change, this still compiles even though BIcConsumer
returns void
. Apparently, return values of method references are ignored when assigned to void functional interfaces!
EDIT:
Oh - I just realized, this could break implementations that override these methods... I think that would be relatively rare but it's possible. What do you think @aepfli @chrfwow ?
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 don't think this would be much of a problem. Providers can just return Awaitable.FINISHED
if they do this synchronously, otherwise it's probably best to return something to get informed about the state update anyway.
Signed-off-by: Todd Baert <[email protected]>
Signed-off-by: Todd Baert <[email protected]>
|
This PR
Related Issues
Fixes #1449