3636import org .apache .doris .journal .bdbje .BDBTool ;
3737import org .apache .doris .journal .bdbje .BDBToolOptions ;
3838import org .apache .doris .persist .meta .MetaReader ;
39+ import org .apache .doris .qe .Coordinator ;
40+ import org .apache .doris .qe .QeProcessorImpl ;
3941import org .apache .doris .qe .QeService ;
4042import org .apache .doris .qe .SimpleScheduler ;
4143import org .apache .doris .service .ExecuteEnv ;
6365import java .nio .channels .OverlappingFileLockException ;
6466import java .nio .file .StandardOpenOption ;
6567import java .time .LocalDate ;
68+ import java .util .List ;
6669import java .util .concurrent .TimeUnit ;
6770import java .util .concurrent .atomic .AtomicBoolean ;
6871
@@ -84,7 +87,10 @@ public class DorisFE {
8487 private static FileLock processFileLock ;
8588
8689 // set to true when all servers are ready.
87- private static AtomicBoolean serverReady = new AtomicBoolean (false );
90+ private static final AtomicBoolean serverReady = new AtomicBoolean (false );
91+
92+ // HTTP server instance, used for graceful shutdown
93+ private static HttpServer httpServer ;
8894
8995 public static void main (String [] args ) {
9096 // Every doris version should have a final meta version, it should not change
@@ -148,7 +154,19 @@ public static void start(String dorisHomeDir, String pidDir, String[] args, Star
148154 }
149155
150156 Log4jConfig .initLogging (dorisHomeDir + "/conf/" );
151- Runtime .getRuntime ().addShutdownHook (new Thread (LogManager ::shutdown ));
157+ // Add shutdown hook for graceful exit
158+ Runtime .getRuntime ().addShutdownHook (new Thread (() -> {
159+ LOG .info ("Received shutdown signal, starting graceful shutdown..." );
160+ serverReady .set (false );
161+ gracefulShutdown ();
162+
163+ // Shutdown HTTP server after main process graceful shutdown is complete
164+ if (httpServer != null ) {
165+ httpServer .shutdown ();
166+ }
167+
168+ LogManager .shutdown ();
169+ }));
152170
153171 // set dns cache ttl
154172 java .security .Security .setProperty ("networkaddress.cache.ttl" , "60" );
@@ -211,7 +229,7 @@ public static void start(String dorisHomeDir, String pidDir, String[] args, Star
211229 feServer .start ();
212230
213231 if (options .enableHttpServer ) {
214- HttpServer httpServer = new HttpServer ();
232+ httpServer = new HttpServer ();
215233 httpServer .setPort (Config .http_port );
216234 httpServer .setHttpsPort (Config .https_port );
217235 httpServer .setMaxHttpPostSize (Config .jetty_server_max_http_post_size );
@@ -242,11 +260,13 @@ public static void start(String dorisHomeDir, String pidDir, String[] args, Star
242260 startMonitor ();
243261
244262 serverReady .set (true );
263+ // JVM will exit when shutdown hook is completed
245264 while (true ) {
246265 Thread .sleep (2000 );
247266 }
267+ LOG .info ("Doris FE main loop exited, shutting down gracefully..." );
248268 } catch (Throwable e ) {
249- // Some exception may thrown before LOG is inited.
269+ // Some exception may throw before LOG is inited.
250270 // So need to print to stdout
251271 e .printStackTrace ();
252272 LOG .error ("" , e );
@@ -599,4 +619,21 @@ public static class StartupOptions {
599619 public static boolean isServerReady () {
600620 return serverReady .get ();
601621 }
622+
623+ private static void gracefulShutdown () {
624+ // wait for all queries to finish
625+ try {
626+ long now = System .currentTimeMillis ();
627+ List <Coordinator > allCoordinators = QeProcessorImpl .INSTANCE .getAllCoordinators ();
628+ while (!allCoordinators .isEmpty () && System .currentTimeMillis () - now < 300 * 1000L ) {
629+ Thread .sleep (1000 );
630+ allCoordinators = QeProcessorImpl .INSTANCE .getAllCoordinators ();
631+ LOG .info ("waiting {} queries to finish before shutdown" , allCoordinators .size ());
632+ }
633+ } catch (Throwable t ) {
634+ LOG .error ("" , t );
635+ }
636+
637+ LOG .info ("graceful shutdown finished" );
638+ }
602639}
0 commit comments