@@ -134,6 +134,14 @@ public int startServer() throws Exception {
134134 ProcessBuilder processBuilder = new ProcessBuilder (command );
135135 processBuilder .redirectErrorStream (true ); // Redirect standard error to the input stream
136136 runningProcess = processBuilder .start ();
137+
138+ // Add shutdown hook to ensure server is closed when Java app exits
139+ try {
140+ Runtime .getRuntime ().addShutdownHook (shutdownHook );
141+ } catch (IllegalStateException ignored ) {
142+ // JVM is already shutting down
143+ }
144+
137145 Thread processThread = new Thread (() -> {
138146 try (BufferedReader reader = new BufferedReader (new InputStreamReader (runningProcess .getInputStream ()))) {
139147 String line ;
@@ -155,6 +163,25 @@ public int startServer() throws Exception {
155163 return port ;
156164 // You can continue with other tasks here
157165 }
166+
167+ private final Thread shutdownHook = new Thread (() -> {
168+ Process p = runningProcess ;
169+ if (p == null ) return ;
170+
171+ try {
172+ // Try graceful termination first
173+ p .destroy (); // sends SIGTERM on Unix, WM_CLOSE/CTRL_BREAK semantics vary on Windows
174+ if (!p .waitFor (3 , java .util .concurrent .TimeUnit .SECONDS )) {
175+ // Fall back to force kill
176+ p .destroyForcibly ();
177+ p .waitFor (2 , java .util .concurrent .TimeUnit .SECONDS );
178+ }
179+ } catch (InterruptedException ie ) {
180+ Thread .currentThread ().interrupt ();
181+ } catch (Exception e ) {
182+ e .printStackTrace ();
183+ }
184+ });
158185
159186 public void stopServer () {
160187 if (runningProcess != null ) {
0 commit comments