Skip to content

Commit 2a54852

Browse files
committed
fix: entity unregister node
When the `unregisterNode` method is called for another NeonBee node, and the executing node has an `EntityVerticle` that was also registered by the other node, the `EntityVerticle` was incorrectly unregistered for the executing node. This fix ensures that the `EntityVerticle` remains registered for the executing node.
1 parent 64d2ac4 commit 2a54852

File tree

3 files changed

+472
-54
lines changed

3 files changed

+472
-54
lines changed

src/main/java/io/neonbee/internal/cluster/entity/ClusterEntityRegistry.java

+44-26
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,9 @@ public class ClusterEntityRegistry implements Registry<String> {
4444
@VisibleForTesting
4545
final WriteSafeRegistry<JsonObject> clusteringInformation;
4646

47-
private final Vertx vertx;
47+
final WriteSafeRegistry<Object> entityRegistry;
4848

49-
private final WriteSafeRegistry<Object> entityRegistry;
49+
private final Vertx vertx;
5050

5151
/**
5252
* Create a new instance of {@link ClusterEntityRegistry}.
@@ -76,8 +76,11 @@ public Future<Void> register(String sharedMapKey, String value) {
7676

7777
@Override
7878
public Future<Void> unregister(String sharedMapKey, String value) {
79-
return Future.all(entityRegistry.unregister(sharedMapKey, value), clusteringInformation
80-
.unregister(getClusterNodeId(), clusterRegistrationInformation(sharedMapKey, value)))
79+
return Future.all(
80+
entityRegistry.unregister(sharedMapKey, value),
81+
clusteringInformation.unregister(
82+
getClusterNodeId(),
83+
clusterRegistrationInformation(sharedMapKey, value)))
8184
.mapEmpty();
8285
}
8386

@@ -123,32 +126,47 @@ Future<Void> removeClusteringInformation(String clusterNodeId) {
123126
* @return the future
124127
*/
125128
public Future<Void> unregisterNode(String clusterNodeId) {
126-
return clusteringInformation.getSharedMap().compose(AsyncMap::entries).compose(map -> {
127-
JsonArray registeredEntities = (JsonArray) map.remove(clusterNodeId);
128-
129-
if (registeredEntities == null) {
130-
// If no entities are registered, return a completed future
131-
return Future.succeededFuture();
132-
}
133-
registeredEntities = registeredEntities.copy();
134-
List<Future<?>> futureList = new ArrayList<>(registeredEntities.size());
135-
for (Object o : registeredEntities) {
136-
if (remove(map, o)) {
137-
JsonObject jo = (JsonObject) o;
138-
String entityName = jo.getString(ENTITY_NAME_KEY);
139-
String qualifiedName = jo.getString(QUALIFIED_NAME_KEY);
140-
futureList.add(unregister(entityName, qualifiedName));
141-
}
142-
}
143-
return Future.join(futureList).mapEmpty();
144-
}).compose(cf -> removeClusteringInformation(clusterNodeId));
129+
return clusteringInformation.getSharedMap()
130+
.compose(AsyncMap::entries)
131+
.compose(map -> {
132+
JsonArray registeredEntities = (JsonArray) map.remove(clusterNodeId);
133+
134+
if (registeredEntities == null) {
135+
// If no entities are registered, return a completed future
136+
return Future.succeededFuture();
137+
}
138+
registeredEntities = registeredEntities.copy();
139+
List<Future<?>> futureList = new ArrayList<>(registeredEntities.size());
140+
for (Object o : registeredEntities) {
141+
if (shouldRemove(map, o)) {
142+
JsonObject jo = (JsonObject) o;
143+
String entityName = jo.getString(ENTITY_NAME_KEY);
144+
String qualifiedName = jo.getString(QUALIFIED_NAME_KEY);
145+
futureList.add(entityRegistry.unregister(entityName, qualifiedName));
146+
}
147+
}
148+
return Future.join(futureList).mapEmpty();
149+
}).compose(cf -> removeClusteringInformation(clusterNodeId));
145150
}
146151

147-
private boolean remove(Map<String, Object> map, Object o) {
152+
/**
153+
* Check if the provided object should be removed from the map.
154+
*
155+
* @param map the map
156+
* @param o the object
157+
* @return true if the object should be removed
158+
*/
159+
private boolean shouldRemove(Map<String, Object> map, Object o) {
148160
for (Map.Entry<String, Object> node : map.entrySet()) {
149161
JsonArray ja = (JsonArray) node.getValue();
150-
if (ja.contains(o)) {
151-
return false;
162+
// Iterate over the JsonArray to determine if it contains the specified object.
163+
// JsonArray#contains cannot be used directly because the types of objects in the JsonArray may differ from
164+
// those returned by the iterator. This discrepancy occurs because JsonArray.Iter#next automatically wraps
165+
// standard Java types into their corresponding Json types.
166+
for (Object object : ja) {
167+
if (object.equals(o)) {
168+
return false;
169+
}
152170
}
153171
}
154172
return true;

0 commit comments

Comments
 (0)