Skip to content
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(apollo-client): add method interestedChangedKeys to ConfigChangeEvent #3666

Merged

Conversation

Anilople
Copy link
Contributor

@Anilople Anilople commented May 8, 2021

What's the purpose of this PR

Let user can get interestedChangedKeys through ConfigChangeEvent

Which issue(s) this PR fixes:

Fixes #3664

Brief changelog

resolve interestedChangedKeys in class AbstractConfig

Follow this checklist to help us incorporate your contribution quickly and easily:

  • Read the Contributing Guide before making this pull request.
  • Write a pull request description that is detailed enough to understand what the pull request does, how, and why.
  • Write necessary unit tests to verify the code.
  • Run mvn clean test to make sure this pull request doesn't break anything.

@@ -450,7 +468,7 @@ public void run() {
String listenerName = listener.getClass().getName();
Transaction transaction = Tracer.newTransaction("Apollo.ConfigChangeListener", listenerName);
try {
listener.onChange(changeEvent);
listener.onChange(resolve(listener, changeEvent));
Copy link
Contributor Author

@Anilople Anilople May 8, 2021

Choose a reason for hiding this comment

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

How about generate a new ConfigChangeEvent here?

Subclass's ConfigChangeEvent + resolved interestedChangedKeys ==> new ConfigChangeEvent

That will change the default behavior of subclass, but still keep compatible.

Copy link
Member

Choose a reason for hiding this comment

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

How about we create a subclass of ConfigChangeEvent, which contains the original config change event and the interested keys so that we don't need to create a new instance?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

When subclasses of AbstractConfig invoke method com.ctrip.framework.apollo.internals.AbstractConfig#fireConfigChange, they don't know about any information of interestedKeys because interestedKeys are saved in AbstractConfig.

If we create a subclass of ConfigChangeEvent, when method com.ctrip.framework.apollo.internals.AbstractConfig#fireConfigChange is invoking, we still need to create a new instance of subclass of ConfigChangeEvent, because the listener need to get this instance?

Copy link
Member

Choose a reason for hiding this comment

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

you are right, I was thinking we may use the composition pattern to avoid create a lot of ConfigChangeEvent instances.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Change ConfigChangeEvent to an abstract class?

public abstract class ConfigChangeEvent {
// content
}

Or create a new class AbstractConfigChangeEvent,

public abstract class AbstractConfigChangeEvent {
  public abstract Set<String> changedKeys();
  public abstract Set<String> interestedChangedKeys();
  public abstract ConfigChange getChange(String key);
  public abstract boolean isChanged(String key);
  public abstract String getNamespace();
}

then let ConfigChangeEvent extends it?

public class ConfigChangeEvent extends AbstractConfigChangeEvent {
// ...
}

Copy link
Member

Choose a reason for hiding this comment

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

My original idea was to create an abstract class or an interface, and then use composition to wrap the original ConfigChangeEvent into InterestedConfigChangeEvent. But the current implementation also looks good to me.

@codecov-commenter
Copy link

codecov-commenter commented May 8, 2021

Codecov Report

Merging #3666 (479a5d2) into master (ff38fe0) will increase coverage by 0.07%.
The diff coverage is 89.65%.

Impacted file tree graph

@@             Coverage Diff              @@
##             master    #3666      +/-   ##
============================================
+ Coverage     50.32%   50.40%   +0.07%     
- Complexity     2374     2389      +15     
============================================
  Files           457      458       +1     
  Lines         14435    14472      +37     
  Branches       1457     1467      +10     
============================================
+ Hits           7264     7294      +30     
- Misses         6665     6674       +9     
+ Partials        506      504       -2     
Impacted Files Coverage Δ
...trip/framework/apollo/model/ConfigChangeEvent.java 88.88% <66.66%> (-11.12%) ⬇️
...rip/framework/apollo/internals/AbstractConfig.java 83.15% <89.79%> (+4.50%) ⬆️
...trip/framework/apollo/internals/DefaultConfig.java 82.97% <100.00%> (ø)
.../apollo/internals/InterestedConfigChangeEvent.java 100.00% <100.00%> (ø)
...ctrip/framework/apollo/internals/SimpleConfig.java 86.84% <100.00%> (ø)
...work/apollo/biz/message/DatabaseMessageSender.java 50.00% <0.00%> (-14.59%) ⬇️
...framework/apollo/openapi/entity/ConsumerAudit.java 42.42% <0.00%> (-6.07%) ⬇️
...rk/apollo/spring/property/SpringValueRegistry.java 83.33% <0.00%> (-5.56%) ⬇️
...mework/apollo/openapi/service/ConsumerService.java 47.57% <0.00%> (-1.95%) ⬇️
.../framework/apollo/spring/property/SpringValue.java 87.71% <0.00%> (-1.76%) ⬇️
... and 3 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update ff38fe0...479a5d2. Read the comment docs.

Copy link
Member

@nobodyiam nobodyiam left a comment

Choose a reason for hiding this comment

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

Thanks for the effort, basically I think it's fine. Please find some comments below.
BTW, I think we need to add some unit test for the new apis.

@@ -450,7 +468,7 @@ public void run() {
String listenerName = listener.getClass().getName();
Transaction transaction = Tracer.newTransaction("Apollo.ConfigChangeListener", listenerName);
try {
listener.onChange(changeEvent);
listener.onChange(resolve(listener, changeEvent));
Copy link
Member

Choose a reason for hiding this comment

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

How about we create a subclass of ConfigChangeEvent, which contains the original config change event and the interested keys so that we don't need to create a new instance?

@github-actions
Copy link

github-actions bot commented May 15, 2021

CLA Assistant Lite bot All contributors have signed the CLA ✍️ ✅

@nobodyiam nobodyiam added this to the 1.9.0 milestone May 23, 2021

UnsupportedOperationConfig config = new UnsupportedOperationConfig();
config.addChangeListener(configChangeListener, Collections.singleton("key-nothing"), Collections.singleton(keyPrefix));
config.fireConfigChange(namespace, Collections.singletonMap(key,
Copy link
Member

Choose a reason for hiding this comment

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

I would suggest we add some irrelavent change here to check whether the interested keys logic works, e.g.

    Map<String, ConfigChange> changes = new HashMap<>();
    changes.put(key, new ConfigChange(namespace, key, "123", "456", PropertyChangeType.MODIFIED));
    changes.put(anotherKey,
        new ConfigChange(namespace, anotherKey, null, "someValue", PropertyChangeType.ADDED));
    config.fireConfigChange(namespace, changes);

and then verify the changedKeys and interestedChangedKeys methods both work

    ConfigChangeListener configChangeListener = spy(new ConfigChangeListener() {
      @Override
      public void onChange(ConfigChangeEvent changeEvent) {
        assertEquals(namespace, changeEvent.getNamespace());
        assertEquals(2, changeEvent.changedKeys().size());
        assertTrue(changeEvent.changedKeys().containsAll(Sets.newHashSet(key, anotherKey)));
        assertEquals(1, changeEvent.interestedChangedKeys().size());
        assertTrue(changeEvent.interestedChangedKeys().contains(key));
        onChangeFuture.set(changeEvent);
      }
    });

@JaredTan95
Copy link
Member

as #3747 merged, please update changs log. :-)

Copy link
Member

@nobodyiam nobodyiam left a comment

Choose a reason for hiding this comment

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

LGTM

@nobodyiam nobodyiam self-requested a review June 9, 2021 00:30
Copy link
Member

@nobodyiam nobodyiam left a comment

Choose a reason for hiding this comment

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

after checking the ci failure, I think there is a bug here.
as the following screenshot shows, the ConfigChangeListener is triggered in 2 for loops, which means it is triggered multiple times.

image

*
* @return how many listener be fired
*/
protected int fireConfigChange(final ConfigChangeEvent changeEvent) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will it break the compability when change return type from void to int?

Copy link
Member

@nobodyiam nobodyiam Jun 10, 2021

Choose a reason for hiding this comment

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

I think it will, since this method is protected, users may have overridden it

@Anilople Anilople requested a review from nobodyiam June 9, 2021 14:06
changes.put("key1", new ConfigChange(namespace, "key1", null, "new-value", PropertyChangeType.ADDED));
ConfigChangeEvent configChangeEvent = new ConfigChangeEvent(namespace, changes);

assertEquals(0, abstractConfig.fireConfigChange(configChangeEvent));
Copy link
Member

Choose a reason for hiding this comment

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

I think we can add a counter in this onChange method to test the times of invocation instead of changing the signature

@Anilople Anilople requested a review from nobodyiam June 10, 2021 12:11
Copy link
Member

@nobodyiam nobodyiam left a comment

Choose a reason for hiding this comment

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

LGTM

@nobodyiam nobodyiam merged commit 44cf586 into apolloconfig:master Jun 11, 2021
@github-actions github-actions bot locked and limited conversation to collaborators Jun 11, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

ApolloConfigChangeListener interestedKeyPrefixes don't filter keys
4 participants