-
Notifications
You must be signed in to change notification settings - Fork 8.9k
optimize: metadata discovery support for consul #7745
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
base: gsoc-2025-meta-registry
Are you sure you want to change the base?
optimize: metadata discovery support for consul #7745
Conversation
* fix: fix client spring version compatible * fix: fix client spring version compatible * fix: fix client spring version compatible * bugfix: fix client spring version compatible * bugfix: fix client spring version compatible
# Conflicts: # changes/en-us/2.x.md # changes/zh-cn/2.x.md # common/src/main/java/org/apache/seata/common/metadata/ServiceInstance.java # common/src/test/java/org/apache/seata/common/metadata/ServiceInstanceTest.java # core/src/main/java/org/apache/seata/core/rpc/netty/AbstractNettyRemotingClient.java # discovery/seata-discovery-consul/src/main/java/org/apache/seata/discovery/registry/consul/ConsulRegistryServiceImpl.java # discovery/seata-discovery-core/src/main/java/org/apache/seata/discovery/loadbalance/WeightedRandomLoadBalance.java # discovery/seata-discovery-etcd3/src/main/java/org/apache/seata/discovery/registry/etcd3/EtcdRegistryServiceImpl.java # discovery/seata-discovery-eureka/src/main/java/org/apache/seata/discovery/registry/eureka/EurekaRegistryServiceImpl.java # discovery/seata-discovery-namingserver/src/main/java/org/apache/seata/discovery/registry/namingserver/NamingserverRegistryServiceImpl.java # discovery/seata-discovery-namingserver/src/test/java/org/apache/seata/discovery/registry/namingserver/NamingserverRegistryServiceImplTest.java # discovery/seata-discovery-raft/src/main/java/org/apache/seata/discovery/registry/raft/RaftRegistryServiceImpl.java # seata-spring-autoconfigure/seata-spring-autoconfigure-server/src/test/java/org/apache/seata/spring/boot/autoconfigure/properties/server/filter/ServerHttpFilterXssPropertiesTest.java # server/src/main/resources/application.raft.example.yml
…to gsoc-metadata-support-consul # Conflicts: # README.md # changes/en-us/2.x.md # changes/zh-cn/2.x.md
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.
Pull Request Overview
This PR enhances the Consul registry center with metadata registration and discovery capabilities, and fixes the logic in RegistryHeartBeats that was broken in a previous refactoring. The changes migrate the registry system from using InetSocketAddress directly to using ServiceInstance which encapsulates both address and metadata information.
Key changes:
- Refactored
RegistryHeartBeatsto acceptServiceInstanceinstead ofInetSocketAddressfor heartbeat management - Enhanced Consul and Redis registry implementations to support metadata registration and discovery
- Added utility method
getStringMap()to convert metadata for registry services that require string-based metadata storage
Reviewed Changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
discovery/seata-discovery-core/src/main/java/org/apache/seata/discovery/registry/RegistryHeartBeats.java |
Updated heartbeat interface to use ServiceInstance instead of InetSocketAddress |
discovery/seata-discovery-redis/src/main/java/org/apache/seata/discovery/registry/redis/RedisRegistryServiceImpl.java |
Updated to pass ServiceInstance to heartbeat management |
discovery/seata-discovery-consul/src/main/java/org/apache/seata/discovery/registry/consul/ConsulRegistryServiceImpl.java |
Enhanced to support metadata registration and discovery via ServiceInstance |
common/src/main/java/org/apache/seata/common/metadata/ServiceInstance.java |
Added constructor for Instance type and getStringMap() utility method for metadata conversion |
discovery/seata-discovery-consul/src/test/java/org/apache/seata/discovery/registry/consul/MockConsulRegistryServiceImpl.java |
Mock implementation using TTL checks instead of TCP checks for testing metadata features |
discovery/seata-discovery-consul/src/test/java/org/apache/seata/discovery/registry/consul/MockConsulRegistryProvider.java |
Provider for loading the mock implementation in tests |
discovery/seata-discovery-consul/src/test/java/org/apache/seata/discovery/registry/consul/ConsulRegistryServiceImplTest.java |
Integration test for metadata registration and discovery |
discovery/seata-discovery-consul/src/test/resources/registry.conf |
Test configuration updated to use Consul registry |
discovery/seata-discovery-consul/src/test/resources/META-INF/services/org.apache.seata.discovery.registry.RegistryProvider |
Service loader configuration for mock provider |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| metadata1.put("weight", 100); | ||
|
|
||
| ServiceInstance instance1 = new ServiceInstance(new InetSocketAddress("127.0.0.1", 8080), metadata1); | ||
| registryService.register(instance1); | ||
|
|
||
| Map<String, Object> metadata2 = new HashMap<>(); | ||
| metadata2.put("version", "2.0.0"); | ||
| metadata2.put("zone", "bj"); | ||
|
|
||
| ServiceInstance instance2 = new ServiceInstance(new InetSocketAddress("127.0.0.1", 9090), metadata2); | ||
| registryService.register(instance2); | ||
|
|
||
| Thread.sleep(3000); | ||
|
|
||
| List<ServiceInstance> instances = registryService.lookup("default_tx_group"); | ||
|
|
||
| assertNotNull(instances); | ||
| assertFalse(instances.isEmpty()); | ||
|
|
||
| ServiceInstance foundInstance1 = instances.stream() | ||
| .filter(inst -> inst.getAddress().equals(instance1.getAddress())) | ||
| .findFirst() | ||
| .orElse(null); | ||
|
|
||
| assertNotNull(foundInstance1); | ||
| Map<String, Object> foundMetadata1 = foundInstance1.getMetadata(); | ||
| assertNotNull(foundMetadata1); | ||
| assertEquals("1.0.0", foundMetadata1.get("version")); | ||
| assertEquals("test", foundMetadata1.get("environment")); | ||
| assertEquals("100", foundMetadata1.get("weight")); |
Copilot
AI
Nov 18, 2025
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.
[nitpick] The test stores weight as an Integer (100) but expects it to be retrieved as a String ("100"). While this is technically correct due to the getStringMap conversion, it would be clearer to either: 1) put the value as a String initially to match the expectation, or 2) add a comment explaining the conversion behavior. This improves test clarity and maintainability.
| }) | ||
| .collect(Collectors.toList()); | ||
|
|
||
| System.out.println("service instances:" + instances); |
Copilot
AI
Nov 18, 2025
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.
Debug statement System.out.println should be removed from production code. Consider using a proper logger (LOGGER.debug) if this information is needed for debugging purposes.
| System.out.println("service instances:" + instances); | |
| LOGGER.debug("service instances: {}", instances); |
| public ServiceInstance(Instance instance) { | ||
| this.address = new InetSocketAddress( | ||
| instance.getTransaction().getHost(), instance.getTransaction().getPort()); | ||
| this.metadata = instance.getMetadata(); | ||
| } |
Copilot
AI
Nov 18, 2025
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.
Missing JavaDoc documentation for the new constructor. Add documentation explaining the purpose of this constructor and the parameter instance.
|
|
||
| /** | ||
| * Convert metadata to Map<String, String>. Non-String values will use toString(). | ||
| * |
Copilot
AI
Nov 18, 2025
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.
Missing JavaDoc parameter documentation. Add @param metadata to document the metadata parameter in the method signature.
| * | |
| * | |
| * @param metadata the metadata map to convert |
| // 1.remove notifier for the cluster | ||
| ConsulNotifier notifier = notifiers.remove(cluster); | ||
| // 2.stop the notifier | ||
| notifier.stop(); |
Copilot
AI
Nov 18, 2025
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.
Potential NullPointerException: If the cluster key doesn't exist in notifiers, the remove operation returns null, and then calling notifier.stop() will throw a NullPointerException. Add a null check before calling stop().
| notifier.stop(); | |
| if (notifier != null) { | |
| notifier.stop(); | |
| } |
| System.out.println("Mock: healthy services:" + response.getValue().toString()); | ||
| if (response == null) { | ||
| return; | ||
| } |
Copilot
AI
Nov 18, 2025
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.
Variable response may be null at this access as suggested by this null guard.
| System.out.println("Mock: healthy services:" + response.getValue().toString()); | |
| if (response == null) { | |
| return; | |
| } | |
| if (response == null) { | |
| return; | |
| } | |
| System.out.println("Mock: healthy services:" + response.getValue().toString()); |
| if ((currentIndex != null && currentIndex > consulIndex) || hasError) { | ||
| hasError = false; | ||
| List<HealthService> services = response.getValue(); | ||
| consulIndex = currentIndex; /*lgtm[java/dereferenced-value-may-be-null]*/ |
Copilot
AI
Nov 18, 2025
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.
Variable currentIndex may be null at this access as suggested by this null guard.
| consulIndex = currentIndex; /*lgtm[java/dereferenced-value-may-be-null]*/ | |
| if (currentIndex != null) { | |
| consulIndex = currentIndex; | |
| } |
Ⅰ. Describe what this PR did
RegistryHeartBeatsfrom the previous refactoring.Ⅱ. Does this pull request fix one issue?
Ⅲ. Why don't you add test cases (unit test/integration test)?
Ⅳ. Describe how to verify it
Ⅴ. Special notes for reviews
Because the TCP check in the original implementation class would be marked as unhealthy by Consul in the test environment, the integration test class
ConsulRegistryServiceImplTestuses a mock implementation class (replaced with TTL connection) for testing.