Skip to content

RUM-2875 Introduce the FeatureContextUpdateLitener API#1829

Merged
mariusc83 merged 1 commit into
feature/sr-web-view-supportfrom
mconstantin/rum-2875/propagate-feature-context-update-through-msb
Jan 30, 2024
Merged

RUM-2875 Introduce the FeatureContextUpdateLitener API#1829
mariusc83 merged 1 commit into
feature/sr-web-view-supportfrom
mconstantin/rum-2875/propagate-feature-context-update-through-msb

Conversation

@mariusc83

Copy link
Copy Markdown
Member

What does this PR do?

A brief description of the change being made with this pull request.

Motivation

What inspired you to submit this pull request?

Additional Notes

Anything else we should know when reviewing?

Review checklist (to be filled by reviewers)

  • Feature or bugfix MUST have appropriate tests (unit, integration, e2e)
  • Make sure you discussed the feature or bugfix with the maintaining team in an Issue
  • Make sure each commit and the PR mention the Issue number (cf the CONTRIBUTING doc)

@mariusc83 mariusc83 self-assigned this Jan 17, 2024
@mariusc83
mariusc83 force-pushed the mconstantin/rum-2875/propagate-feature-context-update-through-msb branch from 4dd25fd to 0632729 Compare January 17, 2024 11:29
) : FeatureScope {

internal val initialized = AtomicBoolean(false)
internal val contextUpdateListeners: ConcurrentHashMap<FeatureContextUpdateListener, Any?> =

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

not sure if I should use a ConcurrentHashMap here or just a Set and make a copy when notifying the listeners to make sure it is concurrent

@mariusc83
mariusc83 force-pushed the mconstantin/rum-2875/propagate-feature-context-update-through-msb branch 3 times, most recently from 1dc0481 to b6e49b2 Compare January 17, 2024 16:08
@mariusc83
mariusc83 marked this pull request as ready for review January 17, 2024 16:12
@mariusc83
mariusc83 requested review from a team as code owners January 17, 2024 16:12
@codecov-commenter

codecov-commenter commented Jan 17, 2024

Copy link
Copy Markdown

Codecov Report

Merging #1829 (0011b35) into feature/sr-web-view-support (13a7578) will increase coverage by 0.03%.
The diff coverage is 69.23%.

Additional details and impacted files
@@                       Coverage Diff                       @@
##           feature/sr-web-view-support    #1829      +/-   ##
===============================================================
+ Coverage                        83.75%   83.78%   +0.03%     
===============================================================
  Files                              472      472              
  Lines                            16598    16623      +25     
  Branches                          2501     2504       +3     
===============================================================
+ Hits                             13900    13926      +26     
- Misses                            2004     2010       +6     
+ Partials                           694      687       -7     
Files Coverage Δ
...ain/kotlin/com/datadog/android/core/DatadogCore.kt 84.10% <90.91%> (+0.41%) ⬆️
...in/com/datadog/android/core/NoOpInternalSdkCore.kt 15.91% <0.00%> (-0.76%) ⬇️
...in/com/datadog/android/core/internal/SdkFeature.kt 89.03% <61.54%> (-2.52%) ⬇️

... and 23 files with indirect coverage changes

Comment on lines +48 to +49
featureName: String,
updateCallback: (context: MutableMap<String, Any?>) -> Unit

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

better to revert, not part of the actual code change.

Comment on lines +59 to +60
internal val contextUpdateListeners: ConcurrentHashMap<FeatureContextUpdateListener, String> =
ConcurrentHashMap()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Seems like it is used like a Set, and value is actually never used. In this case it can be just Collections.newSetFromMap(ConcurrentHashMap()) and placeholder for he value is not needed.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

yes, wanted to use the same thing but not available for API 21 :(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

ah yes...that's not what I tested, I tested the Collections.newKeySet which is a new method, but indeed that one would work also. Tks !!

}

internal fun setContextUpdateListener(listener: FeatureContextUpdateListener) {
synchronized(contextUpdateListeners) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Do we actually need ConcurrentHashMap then if each access that modifies the state of contextUpdateListeners is backed by synchronized?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

yes we need it as I did not want to synchronize when we notify the listeners. When I travers them for notification another thread might remove or add a new one and it will get into ConcurrentModificationException

internalLogger.log(
InternalLogger.Level.WARN,
InternalLogger.Target.USER,
{ CONTEXT_UPDATE_LISTENER_ALREADY_EXISTS.format(Locale.US, wrappedFeature.name) }

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

But we don't actually overwrite anything, do we? Both key and value stay the same.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

yes you are right...unless you are providing a different instance of the same listener. The equals method will say true and we are replacing the previous instance with the new one.

updateCallback(mutableContext)
it.setFeatureContext(featureName, mutableContext)
feature.notifyContextUpdated(mutableContext)
mutableContext

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

why to we need this line?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

oh left over sorry

* @param event the updated context
*/
@AnyThread
fun onContextUpdate(event: Map<String, Any?>)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

In this case, generally speaking, we cannot reuse the same listener object for context updates of the different features.

What if we add a feature name as a first argument? That way we could re-use the same object.

Not an ask or blocker for me, just some brainstorming.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

oh...yeah, it might be better indeed. Let's do this.

@mariusc83
mariusc83 force-pushed the mconstantin/rum-2875/propagate-feature-context-update-through-msb branch 2 times, most recently from 48ecd0c to c54cb2d Compare January 18, 2024 09:49
@mariusc83
mariusc83 requested a review from 0xnm January 18, 2024 09:49
@mariusc83
mariusc83 force-pushed the mconstantin/rum-2875/propagate-feature-context-update-through-msb branch 3 times, most recently from 4ba06aa to 0011b35 Compare January 19, 2024 16:44
0xnm
0xnm previously approved these changes Jan 22, 2024

@0xnm 0xnm left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

lgtm, I left some suggestions

// notify all the other features
features.filter { it.key != featureName }
.forEach { (_, feature) ->
feature.notifyContextUpdated(featureName, mutableContext)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

even though the type on the receiver side is Map here, maybe it is worth to make a copy as a safe-guard?

Suggested change
feature.notifyContextUpdated(featureName, mutableContext)
feature.notifyContextUpdated(featureName, mutableContext.toMap())


companion object {
internal const val CONTEXT_UPDATE_LISTENER_ALREADY_EXISTS =
"Feature \"%s\" already has this listener registered, overwriting it."

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Still there is no overwrite, it is already there. Maybe we can drop the part about overwriting?

}

@Test
fun `𝕄 remove context update listener 𝕎 setContextUpdateListener()`(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
fun `𝕄 remove context update listener 𝕎 setContextUpdateListener()`(
fun `𝕄 remove context update listener 𝕎 removeContextUpdateReceiver()`(

}

@Test
fun `M update registered listeners W notifyContextUpdateListener()`(forge: Forge) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
fun `M update registered listeners W notifyContextUpdateListener()`(forge: Forge) {
fun `M update registered listeners W notifyContextUpdated()`(forge: Forge) {

Comment on lines +562 to +571
val countDownLatch = CountDownLatch(mockListeners.size)
mockListeners.forEach {
Thread {
testedFeature.setContextUpdateListener(it)
countDownLatch.countDown()
}.start()
}

// Then
countDownLatch.await(5, TimeUnit.SECONDS)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Alternatively this can be written without CountDownLatch:

Suggested change
val countDownLatch = CountDownLatch(mockListeners.size)
mockListeners.forEach {
Thread {
testedFeature.setContextUpdateListener(it)
countDownLatch.countDown()
}.start()
}
// Then
countDownLatch.await(5, TimeUnit.SECONDS)
mockListeners.map {
Thread {
testedFeature.setContextUpdateListener(it)
countDownLatch.countDown()
}.apply { start() }
}.forEach { it.join(5, TimeUnit.SECONDS) }
// Then

but not a big deal

@mariusc83
mariusc83 force-pushed the mconstantin/rum-2875/propagate-feature-context-update-through-msb branch from 0011b35 to 6869dff Compare January 29, 2024 08:52
@mariusc83
mariusc83 force-pushed the mconstantin/rum-2875/propagate-feature-context-update-through-msb branch from 6869dff to 474b8b0 Compare January 29, 2024 09:10
@mariusc83
mariusc83 merged commit 2470aa7 into feature/sr-web-view-support Jan 30, 2024
@mariusc83
mariusc83 deleted the mconstantin/rum-2875/propagate-feature-context-update-through-msb branch January 30, 2024 07:57
@xgouchet xgouchet added this to the 2.8.x milestone Apr 5, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants