Copilot commented on code in PR #13058:
URL: https://github.com/apache/cloudstack/pull/13058#discussion_r3309508191


##########
services/console-proxy/server/src/main/java/com/cloud/consoleproxy/ConsoleProxyNoVNCHandler.java:
##########
@@ -93,15 +94,16 @@ public void onConnect(final Session session) throws 
IOException, InterruptedExce
         String websocketUrl = queryMap.get("websocketUrl");
         String sessionUuid = queryMap.get("sessionUuid");
         String clientIp = 
session.getRemoteAddress().getAddress().getHostAddress();
+        boolean sessionRequiresNewViewer = 
Boolean.parseBoolean(queryMap.get("sessionRequiresNewViewer"));
 
-        if (tag == null)
+        if (tag == null) {
             tag = "";
+        }

Review Comment:
   `sessionRequiresNewViewer` is parsed from the query string but never used. 
This is confusing (and conflicts with the PR description about removing 
newer-branch references). Please remove the unused variable/parameter, or wire 
it into the viewer selection logic if it is required on 4.20.



##########
services/console-proxy/server/src/main/java/com/cloud/consoleproxy/ConsoleProxyGCThread.java:
##########
@@ -16,98 +16,119 @@
 // under the License.
 package com.cloud.consoleproxy;
 
+
 import java.io.File;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.Map;
 import java.util.Set;
 
+
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.LogManager;
 
+
 /**
  *
  * ConsoleProxyGCThread does house-keeping work for the process, it helps 
cleanup log files,
  * recycle idle client sessions without front-end activities and report client 
stats to external
  * management software
  */
 public class ConsoleProxyGCThread extends Thread {
-    protected Logger logger = LogManager.getLogger(ConsoleProxyGCThread.class);
+    private static final Logger logger = 
LogManager.getLogger(ConsoleProxyGCThread.class);
 
-    private final static int MAX_SESSION_IDLE_SECONDS = 180;
 
     private final Map<String, ConsoleProxyClient> connMap;
     private final Set<String> removedSessionsSet;
     private long lastLogScan = 0;
 
+
     public ConsoleProxyGCThread(Map<String, ConsoleProxyClient> connMap, 
Set<String> removedSet) {
         this.connMap = connMap;
         this.removedSessionsSet = removedSet;
     }
 
+
     private void cleanupLogging() {
-        if (lastLogScan != 0 && System.currentTimeMillis() - lastLogScan < 
3600000)
+        if (lastLogScan != 0 && System.currentTimeMillis() - lastLogScan < 
3600000) {
             return;
+        }
+
 
         lastLogScan = System.currentTimeMillis();
 
+
         File logDir = new File("./logs");
-        File files[] = logDir.listFiles();
+        File[] files = logDir.listFiles();
         if (files != null) {
             for (File file : files) {
                 if (System.currentTimeMillis() - file.lastModified() >= 
86400000L) {
                     try {
                         file.delete();
                     } catch (Throwable e) {
-                        logger.info("[ignored]"
-                                + "failed to delete file: " + 
e.getLocalizedMessage());
+                        logger.info("[ignored] failed to delete file: " + 
e.getLocalizedMessage());
                     }
                 }
             }
         }
     }
 
+
     @Override
     public void run() {
 
+
         boolean bReportLoad = false;
         long lastReportTick = System.currentTimeMillis();
 
+
         while (true) {
             cleanupLogging();
             bReportLoad = false;
 
+
             if (logger.isDebugEnabled()) {
-                logger.debug(String.format("connMap=%s, removedSessions=%s", 
connMap, removedSessionsSet));
+                logger.debug(String.format("ConsoleProxyGCThread loop: 
connMap=%s, removedSessions=%s", connMap, removedSessionsSet));
             }
-            Set<String> e = connMap.keySet();
-            Iterator<String> iterator = e.iterator();
+            Set<String> keys = connMap.keySet();
+            Iterator<String> iterator = keys.iterator();
             while (iterator.hasNext()) {
                 String key;
                 ConsoleProxyClient client;
 
+
                 synchronized (connMap) {
                     key = iterator.next();
                     client = connMap.get(key);
                 }
 
-                long seconds_unused = (System.currentTimeMillis() - 
client.getClientLastFrontEndActivityTime()) / 1000;
-                if (seconds_unused < MAX_SESSION_IDLE_SECONDS) {
+
+                if (client == null) {
+                    continue;
+                }
+
+
+                long millisecondsUnused = System.currentTimeMillis() - 
client.getClientLastFrontEndActivityTime();
+                if (millisecondsUnused < ConsoleProxy.sessionTimeoutMillis) {
                     continue;
                 }
 
+
                 synchronized (connMap) {
                     connMap.remove(key);
                     bReportLoad = true;
                 }

Review Comment:
   The GC loop iterates `connMap.keySet().iterator()` but removes entries via 
`connMap.remove(key)` while still using the iterator. This can throw 
`ConcurrentModificationException` (and permanently stop the GC thread), 
especially since other threads also modify `connMap`. Please iterate over a 
snapshot of keys/entries or remove via `iterator.remove()` while holding the 
appropriate lock, and keep the close operation outside the lock.



##########
services/console-proxy/server/src/main/java/com/cloud/consoleproxy/ConsoleProxy.java:
##########
@@ -53,23 +56,33 @@
 public class ConsoleProxy {
     protected static Logger LOGGER = LogManager.getLogger(ConsoleProxy.class);
 
+
     public static final int KEYBOARD_RAW = 0;
     public static final int KEYBOARD_COOKED = 1;
 
+
     public static final int VIEWER_LINGER_SECONDS = 180;
 
+    // New: default and effective session timeout (milliseconds) honoured from 
consoleproxy.session.timeout
+    public static final int DEFAULT_SESSION_TIMEOUT_MILLIS = 300000;
+    public static volatile int sessionTimeoutMillis = 
DEFAULT_SESSION_TIMEOUT_MILLIS;
+
+

Review Comment:
   The newly introduced `sessionTimeoutMillis` (ms) and the existing 
`VIEWER_LINGER_SECONDS` (s) now represent two different “idle” thresholds used 
in different places (e.g., `isFrontEndAlive()` vs GC cleanup). This can lead to 
inconsistent behaviour where sessions are considered dead/reused at one timeout 
but only cleaned up at another. Also, parsing/storing the timeout as an `int` 
risks overflow for larger millisecond values. Consider using a single 
long-based timeout source (e.g., `volatile long sessionTimeoutMillis`) and 
deriving any second-based thresholds from it where needed.
   



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