Browse Source

fix: improve nginx control logic and enhance error handling

Jacky 3 weeks ago
parent
commit
4f0a51a716
3 changed files with 73 additions and 19 deletions
  1. 5 5
      api/nginx/control.go
  2. 6 0
      app/src/views/config/InspectConfig.vue
  3. 62 14
      internal/nginx/nginx.go

+ 5 - 5
api/nginx/control.go

@@ -14,7 +14,11 @@ func Reload(c *gin.Context) {
 
 // TestConfig tests the nginx config
 func TestConfig(c *gin.Context) {
-	nginx.Control(nginx.TestConfig).Resp(c)
+	lastResult := nginx.Control(nginx.TestConfig)
+	c.JSON(http.StatusOK, gin.H{
+		"message": lastResult.GetOutput(),
+		"level":   lastResult.GetLevel(),
+	})
 }
 
 // Restart restarts the nginx
@@ -28,10 +32,6 @@ func Restart(c *gin.Context) {
 // Status returns the status of the nginx
 func Status(c *gin.Context) {
 	lastResult := nginx.GetLastResult()
-	if lastResult.IsError() {
-		lastResult.RespError(c)
-		return
-	}
 
 	running := nginx.IsRunning()
 

+ 6 - 0
app/src/views/config/InspectConfig.vue

@@ -36,6 +36,7 @@ defineExpose({
     <AAlert
       v-else-if="data?.level === logLevel.Warn"
       :message="$gettext('Warning')"
+      :banner
       type="warning"
       show-icon
     >
@@ -47,6 +48,7 @@ defineExpose({
     <AAlert
       v-else-if="data?.level > logLevel.Warn"
       :message="$gettext('Error')"
+      :banner
       type="error"
       show-icon
     >
@@ -65,4 +67,8 @@ defineExpose({
 :deep(.ant-alert-description) {
   white-space: pre-line;
 }
+
+:deep(.ant-alert-banner) {
+  padding: 8px 24px;
+}
 </style>

+ 62 - 14
internal/nginx/nginx.go

@@ -2,7 +2,10 @@ package nginx
 
 import (
 	"os"
+	"strconv"
+	"strings"
 	"sync"
+	"syscall"
 	"time"
 
 	"github.com/0xJacky/Nginx-UI/internal/docker"
@@ -33,20 +36,18 @@ func Reload() (stdOut string, stdErr error) {
 	// Clear the modules cache when reloading Nginx
 	clearModulesCache()
 
+	if !IsRunning() {
+		restart()
+		return
+	}
+
 	if settings.NginxSettings.ReloadCmd != "" {
 		return execShell(settings.NginxSettings.ReloadCmd)
 	}
 	return execCommand("nginx", "-s", "reload")
 }
 
-// Restart restarts the nginx
-func Restart() {
-	mutex.Lock()
-	defer mutex.Unlock()
-
-	// Clear the modules cache when restarting Nginx
-	clearModulesCache()
-
+func restart() {
 	// fix(docker): nginx restart always output network error
 	time.Sleep(500 * time.Millisecond)
 
@@ -58,9 +59,12 @@ func Restart() {
 	pidPath := GetPIDPath()
 	daemon := GetSbinPath()
 
-	lastStdOut, lastStdErr = execCommand("start-stop-daemon", "--stop", "--quiet", "--oknodo", "--retry=TERM/30/KILL/5", "--pidfile", pidPath)
-	if lastStdErr != nil {
-		return
+	// Check if nginx is running before attempting to stop it
+	if IsRunning() {
+		lastStdOut, lastStdErr = execCommand("start-stop-daemon", "--stop", "--quiet", "--oknodo", "--retry=TERM/30/KILL/5", "--pidfile", pidPath)
+		if lastStdErr != nil {
+			return
+		}
 	}
 
 	if daemon == "" {
@@ -71,6 +75,17 @@ func Restart() {
 	lastStdOut, lastStdErr = execCommand("start-stop-daemon", "--start", "--quiet", "--pidfile", pidPath, "--exec", daemon)
 }
 
+// Restart restarts the nginx
+func Restart() {
+	mutex.Lock()
+	defer mutex.Unlock()
+
+	// Clear the modules cache when restarting Nginx
+	clearModulesCache()
+
+	restart()
+}
+
 // GetLastOutput returns the last output of the nginx command
 func GetLastResult() *ControlResult {
 	mutex.Lock()
@@ -87,9 +102,42 @@ func IsRunning() bool {
 	case true:
 		return docker.StatPath(pidPath)
 	case false:
-		if fileInfo, err := os.Stat(pidPath); err != nil || fileInfo.Size() == 0 {
-			return false
-		}
+		return isProcessRunning(pidPath)
+	}
+	return false
+}
+
+// isProcessRunning checks if the process with the PID from pidPath is actually running
+func isProcessRunning(pidPath string) bool {
+	// Check if PID file exists
+	if fileInfo, err := os.Stat(pidPath); err != nil || fileInfo.Size() == 0 {
+		return false
+	}
+
+	// Read PID from file
+	pidBytes, err := os.ReadFile(pidPath)
+	if err != nil {
+		return false
+	}
+
+	pidStr := strings.TrimSpace(string(pidBytes))
+	pid, err := strconv.Atoi(pidStr)
+	if err != nil {
+		return false
+	}
+
+	// Cross-platform process existence check
+	process, err := os.FindProcess(pid)
+	if err != nil {
+		return false
+	}
+
+	// On Unix systems, FindProcess always succeeds and returns a Process for the given pid,
+	// regardless of whether the process exists. To test whether the process actually exists,
+	// see whether p.Signal(syscall.Signal(0)) reports an error.
+	err = process.Signal(syscall.Signal(0))
+	if err == nil {
+		// Process exists and we can signal it
 		return true
 	}
 	return false