mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-03-14 01:34:47 +08:00
fix: 解决守护进程停止之后状态读取异常的问题 (#2186)
Refs https://github.com/1Panel-dev/1Panel/issues/2167
This commit is contained in:
parent
38b462eece
commit
ed3d587046
@ -189,21 +189,6 @@ func (b *BaseApi) GetProcess(c *gin.Context) {
|
|||||||
helper.SuccessWithData(c, configs)
|
helper.SuccessWithData(c, configs)
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Tags Host tool
|
|
||||||
// @Summary Load Supervisor process status
|
|
||||||
// @Description 获取 Supervisor 进程状态
|
|
||||||
// @Success 200 {array} response.ProcessStatus
|
|
||||||
// @Security ApiKeyAuth
|
|
||||||
// @Router /host/tool/supervisor/process/load [post]
|
|
||||||
func (b *BaseApi) LoadProcessStatus(c *gin.Context) {
|
|
||||||
datas, err := hostToolService.LoadProcessStatus()
|
|
||||||
if err != nil {
|
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
helper.SuccessWithData(c, datas)
|
|
||||||
}
|
|
||||||
|
|
||||||
// @Tags Host tool
|
// @Tags Host tool
|
||||||
// @Summary Get Supervisor process config
|
// @Summary Get Supervisor process config
|
||||||
// @Description 操作 Supervisor 进程文件
|
// @Description 操作 Supervisor 进程文件
|
||||||
|
@ -3,14 +3,6 @@ package service
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os/exec"
|
|
||||||
"os/user"
|
|
||||||
"path"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
|
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/dto/response"
|
"github.com/1Panel-dev/1Panel/backend/app/dto/response"
|
||||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||||
@ -22,6 +14,11 @@ import (
|
|||||||
"github.com/1Panel-dev/1Panel/backend/utils/systemctl"
|
"github.com/1Panel-dev/1Panel/backend/utils/systemctl"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"gopkg.in/ini.v1"
|
"gopkg.in/ini.v1"
|
||||||
|
"os/exec"
|
||||||
|
"os/user"
|
||||||
|
"path"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type HostToolService struct{}
|
type HostToolService struct{}
|
||||||
@ -34,7 +31,6 @@ type IHostToolService interface {
|
|||||||
GetToolLog(req request.HostToolLogReq) (string, error)
|
GetToolLog(req request.HostToolLogReq) (string, error)
|
||||||
OperateSupervisorProcess(req request.SupervisorProcessConfig) error
|
OperateSupervisorProcess(req request.SupervisorProcessConfig) error
|
||||||
GetSupervisorProcessConfig() ([]response.SupervisorProcessConfig, error)
|
GetSupervisorProcessConfig() ([]response.SupervisorProcessConfig, error)
|
||||||
LoadProcessStatus() ([]response.ProcessStatus, error)
|
|
||||||
OperateSupervisorProcessFile(req request.SupervisorProcessFileReq) (string, error)
|
OperateSupervisorProcessFile(req request.SupervisorProcessFileReq) (string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -377,56 +373,6 @@ func (h *HostToolService) OperateSupervisorProcess(req request.SupervisorProcess
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HostToolService) LoadProcessStatus() ([]response.ProcessStatus, error) {
|
|
||||||
var res []response.ProcessStatus
|
|
||||||
statusLines, _ := cmd.Exec("supervisorctl status")
|
|
||||||
if len(statusLines) == 0 {
|
|
||||||
return res, nil
|
|
||||||
}
|
|
||||||
lines := strings.Split(statusLines, "\n")
|
|
||||||
for _, line := range lines {
|
|
||||||
fields := strings.Fields(line)
|
|
||||||
if len(fields) > 1 {
|
|
||||||
res = append(res, response.ProcessStatus{Name: fields[0]})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
|
||||||
wg.Add(len(res))
|
|
||||||
for i := 0; i < len(res); i++ {
|
|
||||||
go func(index int) {
|
|
||||||
for t := 0; t < 3; t++ {
|
|
||||||
status, err := cmd.ExecWithTimeOut(fmt.Sprintf("supervisorctl status %s", res[index].Name), 2*time.Second)
|
|
||||||
if err != nil {
|
|
||||||
time.Sleep(2 * time.Second)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
fields := strings.Fields(status)
|
|
||||||
if len(fields) < 5 {
|
|
||||||
time.Sleep(2 * time.Second)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
res[index].Name = fields[0]
|
|
||||||
res[index].Status = fields[1]
|
|
||||||
if fields[1] != "RUNNING" {
|
|
||||||
res[index].Msg = strings.Join(fields[2:], " ")
|
|
||||||
break
|
|
||||||
}
|
|
||||||
res[index].PID = strings.TrimSuffix(fields[3], ",")
|
|
||||||
res[index].Uptime = fields[5]
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if len(res[index].Status) == 0 {
|
|
||||||
res[index].Status = "FATAL"
|
|
||||||
res[index].Msg = "Timeout for getting process status"
|
|
||||||
}
|
|
||||||
wg.Done()
|
|
||||||
}(i)
|
|
||||||
}
|
|
||||||
wg.Wait()
|
|
||||||
return res, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *HostToolService) GetSupervisorProcessConfig() ([]response.SupervisorProcessConfig, error) {
|
func (h *HostToolService) GetSupervisorProcessConfig() ([]response.SupervisorProcessConfig, error) {
|
||||||
var (
|
var (
|
||||||
result []response.SupervisorProcessConfig
|
result []response.SupervisorProcessConfig
|
||||||
@ -463,6 +409,7 @@ func (h *HostToolService) GetSupervisorProcessConfig() ([]response.SupervisorPro
|
|||||||
if numprocs, _ := section.GetKey("numprocs"); numprocs != nil {
|
if numprocs, _ := section.GetKey("numprocs"); numprocs != nil {
|
||||||
config.Numprocs = numprocs.Value()
|
config.Numprocs = numprocs.Value()
|
||||||
}
|
}
|
||||||
|
_ = getProcessStatus(&config)
|
||||||
result = append(result, config)
|
result = append(result, config)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -590,3 +537,29 @@ func getProcessName(name, numprocs string) []string {
|
|||||||
}
|
}
|
||||||
return processNames
|
return processNames
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getProcessStatus(config *response.SupervisorProcessConfig) error {
|
||||||
|
var (
|
||||||
|
processNames = []string{"status"}
|
||||||
|
)
|
||||||
|
processNames = append(processNames, getProcessName(config.Name, config.Numprocs)...)
|
||||||
|
output, _ := exec.Command("supervisorctl", processNames...).Output()
|
||||||
|
lines := strings.Split(string(output), "\n")
|
||||||
|
for _, line := range lines {
|
||||||
|
fields := strings.Fields(line)
|
||||||
|
if len(fields) >= 5 {
|
||||||
|
status := response.ProcessStatus{
|
||||||
|
Name: fields[0],
|
||||||
|
Status: fields[1],
|
||||||
|
}
|
||||||
|
if fields[1] == "RUNNING" {
|
||||||
|
status.PID = strings.TrimSuffix(fields[3], ",")
|
||||||
|
status.Uptime = fields[5]
|
||||||
|
} else {
|
||||||
|
status.Msg = strings.Join(fields[2:], " ")
|
||||||
|
}
|
||||||
|
config.Status = append(config.Status, status)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -55,7 +55,6 @@ func (s *HostRouter) InitHostRouter(Router *gin.RouterGroup) {
|
|||||||
hostRouter.POST("/tool/operate", baseApi.OperateTool)
|
hostRouter.POST("/tool/operate", baseApi.OperateTool)
|
||||||
hostRouter.POST("/tool/config", baseApi.OperateToolConfig)
|
hostRouter.POST("/tool/config", baseApi.OperateToolConfig)
|
||||||
hostRouter.POST("/tool/log", baseApi.GetToolLog)
|
hostRouter.POST("/tool/log", baseApi.GetToolLog)
|
||||||
hostRouter.POST("/tool/supervisor/process/load", baseApi.LoadProcessStatus)
|
|
||||||
hostRouter.POST("/tool/supervisor/process", baseApi.OperateProcess)
|
hostRouter.POST("/tool/supervisor/process", baseApi.OperateProcess)
|
||||||
hostRouter.GET("/tool/supervisor/process", baseApi.GetProcess)
|
hostRouter.GET("/tool/supervisor/process", baseApi.GetProcess)
|
||||||
hostRouter.POST("/tool/supervisor/process/file", baseApi.GetProcessFile)
|
hostRouter.POST("/tool/supervisor/process/file", baseApi.GetProcessFile)
|
||||||
|
@ -34,7 +34,7 @@ export const LoadProcessStatus = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const GetSupervisorProcess = () => {
|
export const GetSupervisorProcess = () => {
|
||||||
return http.get<HostTool.SupersivorProcess>(`/hosts/tool/supervisor/process`);
|
return http.get<HostTool.SupersivorProcess[]>(`/hosts/tool/supervisor/process`);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const OperateSupervisorProcessFile = (req: HostTool.ProcessFileReq) => {
|
export const OperateSupervisorProcessFile = (req: HostTool.ProcessFileReq) => {
|
||||||
|
@ -157,7 +157,7 @@ import ConfigSuperVisor from './config/index.vue';
|
|||||||
import { computed, onMounted } from 'vue';
|
import { computed, onMounted } from 'vue';
|
||||||
import Create from './create/index.vue';
|
import Create from './create/index.vue';
|
||||||
import File from './file/index.vue';
|
import File from './file/index.vue';
|
||||||
import { GetSupervisorProcess, LoadProcessStatus, OperateSupervisorProcess } from '@/api/modules/host-tool';
|
import { GetSupervisorProcess, OperateSupervisorProcess } from '@/api/modules/host-tool';
|
||||||
import { GlobalStore } from '@/store';
|
import { GlobalStore } from '@/store';
|
||||||
import i18n from '@/lang';
|
import i18n from '@/lang';
|
||||||
import { HostTool } from '@/api/interface/host-tool';
|
import { HostTool } from '@/api/interface/host-tool';
|
||||||
@ -216,34 +216,46 @@ const search = async () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
loadStatus();
|
let needLoadStatus = false;
|
||||||
try {
|
try {
|
||||||
const res = await GetSupervisorProcess();
|
const res = await GetSupervisorProcess();
|
||||||
data.value = res.data;
|
data.value = res.data;
|
||||||
|
for (const process of data.value) {
|
||||||
|
if (process.status && process.status.length > 0) {
|
||||||
|
process.hasLoad = true;
|
||||||
|
} else {
|
||||||
|
process.hasLoad = false;
|
||||||
|
needLoadStatus = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (needLoadStatus) {
|
||||||
|
setTimeout(loadStatus, 1000);
|
||||||
|
}
|
||||||
} catch (error) {}
|
} catch (error) {}
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
const loadStatus = async () => {
|
const loadStatus = async () => {
|
||||||
await LoadProcessStatus()
|
let needLoadStatus = false;
|
||||||
.then((res) => {
|
try {
|
||||||
let stats = res.data || [];
|
const res = await GetSupervisorProcess();
|
||||||
for (const process of data.value) {
|
const stats = res.data || [];
|
||||||
process.status = [];
|
for (const process of data.value) {
|
||||||
for (const item of stats) {
|
for (const item of stats) {
|
||||||
if (process.name === item.name.split(':')[0]) {
|
if (process.name === item.name) {
|
||||||
process.status.push(item);
|
if (item.status && item.status.length > 0) {
|
||||||
|
process.status = item.status;
|
||||||
|
process.hasLoad = true;
|
||||||
|
} else {
|
||||||
|
needLoadStatus = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
process.hasLoad = true;
|
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
.catch(() => {
|
if (needLoadStatus) {
|
||||||
for (const process of data.value) {
|
setTimeout(loadStatus, 2000);
|
||||||
process.status = [{ name: '-', status: 'FATAL', msg: i18n.global.t('tool.supervisor.loadStatusErr') }];
|
}
|
||||||
process.hasLoad = true;
|
} catch (error) {}
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const mobile = computed(() => {
|
const mobile = computed(() => {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user