RockteMQ-AI commented on code in PR #386:
URL: https://github.com/apache/rocketmq-connect/pull/386#discussion_r3839542169


##########
rocketmq-connect-runtime/src/main/java/org/apache/rocketmq/connect/runtime/service/ConfigManagementServiceImpl.java:
##########
@@ -463,6 +537,47 @@ private void processDeleteConnectorRecord(String 
connectorName, SchemaAndValue s
         }
     }
 
+    /**
+     * process restarte connector
+     *
+     * @param connectorName
+     * @param schemaAndValue
+     */
+    private void processRestartConnectorRecord(String connectorName, 
SchemaAndValue schemaAndValue) {
+        processDeleteConnectorRecord(connectorName, schemaAndValue);
+        processTargetStateRecord(connectorName, schemaAndValue);
+    }
+
+    /**
+     * process restart task
+     *

Review Comment:
   processRestartTaskRecord reads FIELD_STATE from the struct, but 
TASK_RESTART_CONFIGURATION_V0 only defines FIELD_EPOCH. struct.get(FIELD_STATE) 
returns null, and TargetState.valueOf(targetState.toString()) on line ~560 
throws NullPointerException. Unlike processTargetStateRecord which validates 
with `instanceof String` before use, this method has no null check. The entire 
task-restart path is broken and will always fail with NPE.



##########
rocketmq-connect-runtime/src/main/java/org/apache/rocketmq/connect/runtime/service/ConfigManagementServiceImpl.java:
##########
@@ -463,6 +537,47 @@ private void processDeleteConnectorRecord(String 
connectorName, SchemaAndValue s
         }
     }
 
+    /**

Review Comment:
   processRestartConnectorRecord calls processDeleteConnectorRecord then 
processTargetStateRecord. The restart schema CONNECTOR_RESTART_CONFIGURATION_V0 
only has FIELD_EPOCH, but processTargetStateRecord expects FIELD_STATE (per 
TARGET_STATE_V0). Since struct.get(FIELD_STATE) returns null, the `instanceof 
String` check fails and the method logs an error and returns without doing 
anything. Effectively, "restart connector" only deletes the connector — there 
is no mechanism to re-create or re-start it with its previous config.



##########
rocketmq-connect-runtime/src/main/java/org/apache/rocketmq/connect/runtime/service/memory/MemoryConfigManagementServiceImpl.java:
##########
@@ -53,7 +56,30 @@ public class MemoryConfigManagementServiceImpl extends 
AbstractConfigManagementS
      */
     private ConnectorConfigUpdateListener connectorConfigUpdateListener;
 
-    public MemoryConfigManagementServiceImpl() {}
+    public static final String RESTART_CONNECTOR_PREFIX = "restart-";
+
+    public static final String TASK_PREFIX = "task-";
+
+    private static final String FIELD_EPOCH = "epoch";
+

Review Comment:
   The `dataSynchronizer` and `converter` fields are newly declared but never 
initialized — the existing initialize() method body was not modified to assign 
them, and MemoryConfigManagementServiceImpl has no 
ConfigChangeCallback/onCompletion handler. Both restartConnector() and 
restartTask() call dataSynchronizer.send() and converter.fromConnectData(), 
which will throw NullPointerException. The memory implementation should restart 
directly against the local stores rather than routing through a 
DataSynchronizer that does not exist.



##########
rocketmq-connect-runtime/src/main/java/org/apache/rocketmq/connect/runtime/service/ConfigManagementServiceImpl.java:
##########
@@ -463,6 +537,47 @@ private void processDeleteConnectorRecord(String 
connectorName, SchemaAndValue s
         }
     }
 
+    /**
+     * process restarte connector
+     *
+     * @param connectorName
+     * @param schemaAndValue
+     */

Review Comment:
   processRestartTaskRecord receives `taskNum` but never uses it. The method 
removes the entire connector config and all task configs from both stores, then 
triggers a global rebalance — this restarts the whole connector, not a single 
task. The REST endpoint exposes per-task restart semantics that are not honored.



##########
rocketmq-connect-runtime/src/main/java/org/apache/rocketmq/connect/runtime/service/ConfigManagementServiceImpl.java:
##########
@@ -433,6 +495,18 @@ public void onCompletion(Throwable error, String key, 
byte[] value) {
                 String connectorName = 
key.substring(DELETE_CONNECTOR_PREFIX.length());
                 processDeleteConnectorRecord(connectorName, schemaAndValue);
 
+            } else if (key.startsWith(RESTART_CONNECTOR_PREFIX)) {
+                if (key.contains(TASK_PREFIX)) {

Review Comment:
   The onCompletion dispatcher uses `key.contains(TASK_PREFIX)` ("task-") to 
distinguish task-restart from connector-restart keys. Since all task-restart 
keys start with "restart-task-", the check should be 
`key.startsWith(RESTART_CONNECTOR_PREFIX + TASK_PREFIX)`. With `contains`, any 
connector whose name includes "task-" (e.g. "my-task-connector") will be 
misrouted to the task-restart branch. For short names like "task-x" this also 
causes StringIndexOutOfBoundsException because substring(13, lastIndex) has 
begin > end when the key has no task-number suffix.



##########
rocketmq-connect-runtime/src/main/java/org/apache/rocketmq/connect/runtime/service/ConfigManagementServiceImpl.java:
##########
@@ -98,48 +107,62 @@ public static String DELETE_CONNECTOR_KEY(String 
connectorName) {
      * start signal
      */
     public static final Schema START_SIGNAL_V0 = SchemaBuilder.struct()
-            .field(START_SIGNAL, SchemaBuilder.string().build())
-            .build();
+        .field(START_SIGNAL, SchemaBuilder.string().build())
+        .build();
 
     /**
      * connector configuration
      */
     public static final Schema CONNECTOR_CONFIGURATION_V0 = 
SchemaBuilder.struct()
-            .field(FIELD_STATE, SchemaBuilder.string().build())
-            .field(FIELD_EPOCH, SchemaBuilder.int64().build())
-            .field(FIELD_PROPS,
-                    SchemaBuilder.map(
-                            SchemaBuilder.string().optional().build(),
-                            SchemaBuilder.string().optional().build()
-                    ).build())
-            .build();
+        .field(FIELD_STATE, SchemaBuilder.string().build())
+        .field(FIELD_EPOCH, SchemaBuilder.int64().build())
+        .field(FIELD_PROPS,

Review Comment:
   RESTART_TASK_KEY and RESTART_CONNECTOR_KEY can collide. For example, 
RESTART_CONNECTOR_KEY("task-conn-0") produces "restart-task-conn-0", identical 
to RESTART_TASK_KEY("conn", 0). The key format uses simple string concatenation 
without a delimiter that cannot appear in connector names, making collisions 
possible. Consider a format that unambiguously separates the namespace, 
connector name, and task id.



##########
rocketmq-connect-runtime/src/main/java/org/apache/rocketmq/connect/runtime/rest/RestHandler.java:
##########
@@ -236,6 +240,28 @@ private void handleStopAllConnector(Context context) {
         }
     }
 
+    private void handleRestartConnector(Context context) {
+        try {
+            String connectorName = context.pathParam(CONNECTOR_NAME);
+            connectController.restartConnector(connectorName);
+            context.json(new HttpResponse<>(context.status(), "Connector [" + 
connectorName + "] restarted successfully"));
+        } catch (Exception e) {
+            log.error("Restart connector failed .", e);
+            context.json(new 
ErrorMessage(HttpStatus.INTERNAL_SERVER_ERROR_500, e.getMessage()));
+        }
+    }
+
+    public void handleRestartTask(Context context) {
+        try {
+            String connectorName = context.pathParam(CONNECTOR_NAME);

Review Comment:
   handleRestartTask is declared public while handleRestartConnector and all 
other handler methods in this class are private. This is likely unintentional 
and should be private for consistency.



##########
rocketmq-connect-runtime/src/test/java/org/apache/rocketmq/connect/runtime/controller/distributed/TestConfigManagementService.java:
##########
@@ -58,6 +58,16 @@ public void deleteConnectorConfig(String connectorName) {
 
     }
 
+    @Override

Review Comment:
   No test coverage for the restart functionality. The new interface methods 
restartConnector and restartTask are empty stubs in the test mock, and no unit 
or integration tests exercise the restart REST endpoints, the restart record 
processing, or the failure paths (nonexistent connector, invalid task id). 
Given the logic bugs present, tests are essential.



##########
rocketmq-connect-runtime/src/test/java/org/apache/rocketmq/connect/runtime/connectorwrapper/ServerResponseMocker.java:
##########
@@ -98,7 +98,7 @@ public void shutdown() {
         }
         Future<?> future = eventLoopGroup.shutdownGracefully();
         try {
-            future.get();
+            Object o = future.get();

Review Comment:
   The change from `future.get()` to `Object o = future.get()` introduces an 
unused local variable with no functional purpose. If the goal was to suppress 
an unused-return-value warning, a comment or @SuppressWarnings would be 
clearer. This change appears unrelated to the PR's restart feature.



##########
rocketmq-connect-runtime/src/main/java/org/apache/rocketmq/connect/runtime/service/ConfigManagementServiceImpl.java:
##########
@@ -463,6 +537,47 @@ private void processDeleteConnectorRecord(String 
connectorName, SchemaAndValue s
         }
     }
 
+    /**
+     * process restarte connector
+     *
+     * @param connectorName
+     * @param schemaAndValue
+     */
+    private void processRestartConnectorRecord(String connectorName, 
SchemaAndValue schemaAndValue) {
+        processDeleteConnectorRecord(connectorName, schemaAndValue);
+        processTargetStateRecord(connectorName, schemaAndValue);
+    }
+
+    /**
+     * process restart task
+     *
+     * @param connectorName
+     * @param taskNum
+     * @param schemaAndValue

Review Comment:
   The cast `(Long) epoch` is performed without an `instanceof Long` 
validation, unlike the established pattern in processTargetStateRecord and 
mergeConnectConfig. If the deserialized value is not a Long (e.g., Integer from 
some JSON converters, or null), this throws ClassCastException or 
NullPointerException. Add an instanceof guard consistent with the rest of the 
file.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to