@@ -7,9 +7,11 @@ import (
77 "log"
88 "net/http"
99 "os"
10+ "os/exec"
1011 "os/signal"
1112 "path/filepath"
1213 "syscall"
14+ "sync/atomic"
1315 "time"
1416
1517 "github.com/awsl-project/maxx/internal/adapter/client"
@@ -399,6 +401,81 @@ func main() {
399401 codexOAuthServer := core .NewCodexOAuthServer (codexHandler )
400402 codexHandler .SetOAuthServer (codexOAuthServer )
401403
404+ var restartInProgress int32
405+
406+ shutdownServer := func (reason string ) {
407+ log .Printf ("Initiating graceful shutdown (%s)..." , reason )
408+
409+ // Step 1: Wait for active proxy requests to complete
410+ activeCount := requestTracker .ActiveCount ()
411+ if activeCount > 0 {
412+ log .Printf ("Waiting for %d active proxy requests to complete..." , activeCount )
413+ completed := requestTracker .GracefulShutdown (core .GracefulShutdownTimeout )
414+ if ! completed {
415+ log .Printf ("Graceful shutdown timeout, some requests may be interrupted" )
416+ } else {
417+ log .Printf ("All proxy requests completed successfully" )
418+ }
419+ } else {
420+ // Mark as shutting down to reject new requests
421+ requestTracker .GracefulShutdown (0 )
422+ log .Printf ("No active proxy requests" )
423+ }
424+
425+ // Step 2: Stop pprof manager
426+ shutdownCtx , cancel := context .WithTimeout (context .Background (), core .HTTPShutdownTimeout )
427+ defer cancel ()
428+
429+ // Stop background cleanup task
430+ cleanupCancel ()
431+
432+ // Stop pprof manager
433+ if err := pprofMgr .Stop (shutdownCtx ); err != nil {
434+ log .Printf ("Warning: Failed to stop pprof manager: %v" , err )
435+ }
436+
437+ // Stop Codex OAuth server
438+ if err := codexOAuthServer .Stop (shutdownCtx ); err != nil {
439+ log .Printf ("Warning: Failed to stop Codex OAuth server: %v" , err )
440+ }
441+
442+ // Step 3: Shutdown HTTP server
443+ if err := server .Shutdown (shutdownCtx ); err != nil {
444+ log .Printf ("HTTP server graceful shutdown failed: %v, forcing close" , err )
445+ if closeErr := server .Close (); closeErr != nil {
446+ log .Printf ("Force close error: %v" , closeErr )
447+ }
448+ }
449+ }
450+
451+ restartServer := func () error {
452+ if ! atomic .CompareAndSwapInt32 (& restartInProgress , 0 , 1 ) {
453+ return fmt .Errorf ("restart already in progress" )
454+ }
455+
456+ shutdownServer ("restart" )
457+
458+ executable , err := os .Executable ()
459+ if err != nil {
460+ return fmt .Errorf ("failed to locate executable: %w" , err )
461+ }
462+
463+ cmd := exec .Command (executable , os .Args [1 :]... )
464+ cmd .Stdout = os .Stdout
465+ cmd .Stderr = os .Stderr
466+ cmd .Env = os .Environ ()
467+
468+ if err := cmd .Start (); err != nil {
469+ return fmt .Errorf ("failed to start new process: %w" , err )
470+ }
471+
472+ log .Printf ("[Admin] Started new process (pid=%d). Exiting current process." , cmd .Process .Pid )
473+ os .Exit (0 )
474+ return nil
475+ }
476+
477+ adminHandler .SetRestartFunc (restartServer )
478+
402479 // Start server in goroutine
403480 log .Printf ("Starting Maxx server %s on %s" , version .Info (), * addr )
404481 log .Printf ("Data directory: %s" , dataDirPath )
@@ -425,47 +502,7 @@ func main() {
425502 signal .Notify (sigCh , syscall .SIGINT , syscall .SIGTERM )
426503 sig := <- sigCh
427504 log .Printf ("Received signal %v, initiating graceful shutdown..." , sig )
428-
429- // Step 1: Wait for active proxy requests to complete
430- activeCount := requestTracker .ActiveCount ()
431- if activeCount > 0 {
432- log .Printf ("Waiting for %d active proxy requests to complete..." , activeCount )
433- completed := requestTracker .GracefulShutdown (core .GracefulShutdownTimeout )
434- if ! completed {
435- log .Printf ("Graceful shutdown timeout, some requests may be interrupted" )
436- } else {
437- log .Printf ("All proxy requests completed successfully" )
438- }
439- } else {
440- // Mark as shutting down to reject new requests
441- requestTracker .GracefulShutdown (0 )
442- log .Printf ("No active proxy requests" )
443- }
444-
445- // Step 2: Stop pprof manager
446- shutdownCtx , cancel := context .WithTimeout (context .Background (), core .HTTPShutdownTimeout )
447- defer cancel ()
448-
449- // Stop background cleanup task
450- cleanupCancel ()
451-
452- // Stop pprof manager
453- if err := pprofMgr .Stop (shutdownCtx ); err != nil {
454- log .Printf ("Warning: Failed to stop pprof manager: %v" , err )
455- }
456-
457- // Stop Codex OAuth server
458- if err := codexOAuthServer .Stop (shutdownCtx ); err != nil {
459- log .Printf ("Warning: Failed to stop Codex OAuth server: %v" , err )
460- }
461-
462- // Step 3: Shutdown HTTP server
463- if err := server .Shutdown (shutdownCtx ); err != nil {
464- log .Printf ("HTTP server graceful shutdown failed: %v, forcing close" , err )
465- if closeErr := server .Close (); closeErr != nil {
466- log .Printf ("Force close error: %v" , closeErr )
467- }
468- }
505+ shutdownServer (fmt .Sprintf ("signal %v" , sig ))
469506
470507 log .Printf ("Server stopped" )
471508}
0 commit comments