diff --git a/genkit/src/main/java/com/google/genkit/Genkit.java b/genkit/src/main/java/com/google/genkit/Genkit.java index aa7be1070..67314e07e 100644 --- a/genkit/src/main/java/com/google/genkit/Genkit.java +++ b/genkit/src/main/java/com/google/genkit/Genkit.java @@ -1927,13 +1927,14 @@ private void startReflectionServer() { private void startReflectionServerV1() { try { - int port = options.getReflectionPort(); - reflectionServer = new ReflectionServer(registry, port, options.getName()); + int basePort = options.getReflectionPort(); + reflectionServer = new ReflectionServer(registry, basePort, options.getName()); reflectionServer.start(); - logger.info("Reflection server started on port {}", port); + int actualPort = reflectionServer.getPort(); + logger.info("Reflection server started on port {}", actualPort); // Write runtime file with matching runtime ID - RuntimeFileWriter.write(port, reflectionServer.getRuntimeId()); + RuntimeFileWriter.write(actualPort, reflectionServer.getRuntimeId()); } catch (Exception e) { logger.error("Failed to start reflection server", e); throw new GenkitException("Failed to start reflection server", e); diff --git a/genkit/src/main/java/com/google/genkit/ReflectionServer.java b/genkit/src/main/java/com/google/genkit/ReflectionServer.java index 01b8a7a90..bcdad9cce 100644 --- a/genkit/src/main/java/com/google/genkit/ReflectionServer.java +++ b/genkit/src/main/java/com/google/genkit/ReflectionServer.java @@ -58,7 +58,7 @@ public class ReflectionServer { private static final Logger logger = LoggerFactory.getLogger(ReflectionServer.class); private final Registry registry; - private final int port; + private int port; private Server server; private String runtimeId; private EvaluationManager evaluationManager; @@ -90,24 +90,61 @@ public String getRuntimeId() { return runtimeId; } + /** Gets the active reflection server port. */ + public int getPort() { + return port; + } + /** - * Starts the reflection server. + * Starts the reflection server by trying ports in the range [basePort, basePort + 100]. * - * @throws Exception if the server fails to start + * @throws Exception if the server fails to start across the port range */ public void start() throws Exception { - server = new Server(); - - // Configure connector with extended idle timeout for long-running operations - // (e.g., video generation can take several minutes) - ServerConnector connector = new ServerConnector(server); - connector.setPort(port); - connector.setIdleTimeout(900000); // 15 minutes idle timeout - server.addConnector(connector); - - server.setHandler(new ReflectionHandler()); - server.start(); - logger.info("Reflection server started on port {}", port); + int basePort = port; + int maxPort = basePort + 100; + Exception lastException = null; + + for (int p = basePort; p <= maxPort; p++) { + Server candidateServer = null; + try { + candidateServer = new Server(); + + // Configure connector with extended idle timeout for long-running operations + // (e.g., video generation can take several minutes) + ServerConnector connector = new ServerConnector(candidateServer); + connector.setPort(p); + connector.setIdleTimeout(900000); // 15 minutes idle timeout + candidateServer.addConnector(connector); + + candidateServer.setHandler(new ReflectionHandler()); + candidateServer.start(); + + this.server = candidateServer; + this.port = connector.getLocalPort(); + logger.info("Reflection server started on port {}", this.port); + return; + } catch (Exception e) { + lastException = e; + if (candidateServer != null) { + try { + candidateServer.stop(); + } catch (Exception ex) { + // Ignore stop errors during cleanup + } + } + logger.debug("Failed to start reflection server on port {}, trying next...", p); + } + } + + logger.error( + "Failed to start reflection server across port range {}..{}", + basePort, + maxPort, + lastException); + throw new GenkitException( + "Failed to start reflection server across port range " + basePort + ".." + maxPort, + lastException); } /**