Copilot commented on code in PR #7826:
URL: https://github.com/apache/incubator-seata/pull/7826#discussion_r2612671833


##########
server/pom.xml:
##########
@@ -301,7 +301,6 @@
         <dependency>
             <groupId>com.squareup.okhttp3</groupId>
             <artifactId>okhttp</artifactId>

Review Comment:
   The okhttp3 dependency scope has been changed from 'test' to compile 
(default), but the dependency appears to only be used in test code 
(ClusterControllerTest.java). This unnecessarily includes okhttp3 as a runtime 
dependency in production builds. The scope should remain as 'test' unless there 
is production code that requires it.
   ```suggestion
               <artifactId>okhttp</artifactId>
               <scope>test</scope>
   ```



##########
server/src/test/java/org/apache/seata/server/controller/ClusterControllerTest.java:
##########
@@ -152,7 +150,57 @@ public void run() {
     }
 
     @Test
-    @Order(4)
+    @Order(5)
+    void watch_withHttp2() throws Exception {
+        CountDownLatch latch = new CountDownLatch(1);
+
+        Map<String, String> headers = new HashMap<>();
+        headers.put(HTTP.CONTENT_TYPE, 
ContentType.APPLICATION_FORM_URLENCODED.getMimeType());
+
+        Map<String, String> params = new HashMap<>();
+        params.put("default-test", "1");
+
+        Thread thread = new Thread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    Thread.sleep(2000);
+                } catch (InterruptedException e) {
+                    throw new RuntimeException(e);
+                }
+                ((ApplicationEventPublisher) 
ObjectHolder.INSTANCE.getObject(OBJECT_KEY_SPRING_APPLICATION_CONTEXT))
+                        .publishEvent(new ClusterChangeEvent(this, 
"default-test", 2, true));
+            }

Review Comment:
   The test uses an anonymous Runnable class with explicit override annotation, 
which is verbose. Consider using a lambda expression for cleaner code: `Thread 
thread = new Thread(() -> { ... });` This improves readability and follows 
modern Java coding practices.
   ```suggestion
           Thread thread = new Thread(() -> {
               try {
                   Thread.sleep(2000);
               } catch (InterruptedException e) {
                   throw new RuntimeException(e);
               }
               ((ApplicationEventPublisher) 
ObjectHolder.INSTANCE.getObject(OBJECT_KEY_SPRING_APPLICATION_CONTEXT))
                       .publishEvent(new ClusterChangeEvent(this, 
"default-test", 2, true));
   ```



##########
server/src/main/java/org/apache/seata/server/cluster/manager/ClusterWatcherManager.java:
##########
@@ -107,22 +111,33 @@ private void sendWatcherResponse(Watcher<HttpContext> 
watcher, HttpResponseStatu
             return;
         }
         ChannelHandlerContext ctx = context.getContext();
+        if (!ctx.channel().isActive()) {
+            logger.warn(
+                    "Netty channel is not active for watcher on group {}, 
cannot send response.", watcher.getGroup());
+            return;
+        }
+
         if (!context.isHttp2()) {
-            if (ctx.channel().isActive()) {
-                HttpResponse response =
-                        new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, 
nettyStatus, Unpooled.EMPTY_BUFFER);
-                response.headers().set(HttpHeaderNames.CONTENT_LENGTH, 0);
+            // HTTP/1.1 response
+            HttpResponse response =
+                    new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, 
nettyStatus, Unpooled.EMPTY_BUFFER);
+            response.headers().set(HttpHeaderNames.CONTENT_LENGTH, 0);
 
-                if (!context.isKeepAlive()) {
-                    
ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
-                } else {
-                    ctx.writeAndFlush(response);
-                }
+            if (!context.isKeepAlive()) {
+                
ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
             } else {
-                logger.warn(
-                        "Netty channel is not active for watcher on group {}, 
cannot send response.",
-                        watcher.getGroup());
+                ctx.writeAndFlush(response);
             }
+        } else {
+            // HTTP/2 response (h2c support)
+            // Send headers frame
+            Http2Headers headers = new 
DefaultHttp2Headers().status(nettyStatus.codeAsText());
+            headers.set(HttpHeaderNames.CONTENT_LENGTH, "0");
+            ctx.write(new DefaultHttp2HeadersFrame(headers));
+
+            // Send empty data frame with endStream=true to close the stream
+            ctx.write(new DefaultHttp2DataFrame(Unpooled.EMPTY_BUFFER, true));

Review Comment:
   The HTTP/2 response handling does not include error handling for write 
failures. Unlike the HTTP/1.1 path which can use ChannelFutureListener.CLOSE 
for non-keepalive connections, the HTTP/2 path uses separate write operations 
without checking their success. Consider adding listeners to the write 
operations to handle failures or at least log them, similar to how HTTP/1.1 
handles the writeAndFlush result.
   ```suggestion
               ctx.write(new DefaultHttp2DataFrame(Unpooled.EMPTY_BUFFER, true))
                   .addListener(future -> {
                       if (!future.isSuccess()) {
                           logger.warn("Failed to write HTTP/2 response for 
watcher on group {}: {}", watcher.getGroup(), future.cause().toString());
                       }
                   });
   ```



-- 
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]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to