fix: 解决 Node 运行环境状态异常问题 (#4197)

This commit is contained in:
zhengkunwang 2024-03-15 15:36:07 +08:00 committed by GitHub
parent a33eabb4f0
commit 6ce35b723b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 144 additions and 28 deletions

View file

@ -203,3 +203,19 @@ func (b *BaseApi) OperateNodeModules(c *gin.Context) {
}
helper.SuccessWithOutData(c)
}
// @Tags Runtime
// @Summary Sync runtime status
// @Description 同步运行环境状态
// @Accept json
// @Success 200
// @Security ApiKeyAuth
// @Router /runtimes/sync [post]
func (b *BaseApi) SyncStatus(c *gin.Context) {
err := runtimeService.SyncRuntimeStatus()
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithOutData(c)
}

View file

@ -42,6 +42,7 @@ type IRuntimeService interface {
GetNodeModules(req request.NodeModuleReq) ([]response.NodeModule, error)
OperateNodeModules(req request.NodeModuleOperateReq) error
SyncForRestart() error
SyncRuntimeStatus() error
}
func NewRuntimeService() IRuntimeService {
@ -586,3 +587,16 @@ func (r *RuntimeService) SyncForRestart() error {
}
return nil
}
func (r *RuntimeService) SyncRuntimeStatus() error {
runtimes, err := runtimeRepo.List()
if err != nil {
return err
}
for _, runtime := range runtimes {
if runtime.Type == constant.RuntimeNode {
_ = SyncRuntimeContainerStatus(&runtime)
}
}
return nil
}

View file

@ -181,33 +181,20 @@ func SyncRuntimeContainerStatus(runtime *model.Runtime) error {
}
container := containers[0]
interval := 10 * time.Second
retries := 60
for i := 0; i < retries; i++ {
resp, err := cli.InspectContainer(container.ID)
if err != nil {
time.Sleep(interval)
continue
switch container.State {
case "exited":
runtime.Status = constant.RuntimeError
case "running":
runtime.Status = constant.RuntimeRunning
case "paused":
runtime.Status = constant.RuntimeStopped
default:
if runtime.Status != constant.RuntimeBuildIng {
runtime.Status = constant.RuntimeStopped
}
if resp.State.Health != nil {
status := strings.ToLower(resp.State.Health.Status)
switch status {
case "starting":
runtime.Status = constant.RuntimeStarting
_ = runtimeRepo.Save(runtime)
case "healthy":
runtime.Status = constant.RuntimeRunning
_ = runtimeRepo.Save(runtime)
return nil
case "unhealthy":
runtime.Status = constant.RuntimeUnhealthy
_ = runtimeRepo.Save(runtime)
return nil
}
}
time.Sleep(interval)
}
return nil
return runtimeRepo.Save(runtime)
}
func buildRuntime(runtime *model.Runtime, oldImageID string, rebuild bool) {

View file

@ -20,6 +20,7 @@ func (r *RuntimeRouter) InitRouter(Router *gin.RouterGroup) {
groupRouter.POST("/del", baseApi.DeleteRuntime)
groupRouter.POST("/update", baseApi.UpdateRuntime)
groupRouter.GET("/:id", baseApi.GetRuntime)
groupRouter.POST("/sync", baseApi.SyncStatus)
groupRouter.POST("/node/package", baseApi.GetNodePackageRunScript)
groupRouter.POST("/operate", baseApi.OperateRuntime)

View file

@ -58,3 +58,7 @@ export const UpdatePHPExtensions = (req: Runtime.PHPExtensionsUpdate) => {
export const DeletePHPExtensions = (req: Runtime.PHPExtensionsDelete) => {
return http.post<any>(`/runtimes/php/extensions/del`, req);
};
export const SyncRuntime = () => {
return http.post(`/runtimes/sync`, {});
};

View file

@ -2240,6 +2240,35 @@ const message = {
javaFileter: 'Java Dangerous File Filtering',
scannerFilter: 'Scanner filter',
escapeFilter: 'escape filter',
customRule: 'custom rule',
httpMethod: 'HTTP method filter',
fileExt: 'File upload limit',
fileExtHelper: 'File extensions that are prohibited from uploading',
deny: 'forbidden',
allow: 'only allow',
field: 'match object',
pattern: 'matching condition',
ruleContent: 'match content',
contain: 'include',
equal: 'equal',
regex: 'regular expression',
notEqual: 'Not equal to',
customRuleHelper: 'Perform corresponding actions based on condition matching',
actionAllow: 'Allow',
blockIP: 'Block IP',
code: 'return status code',
noRes: 'Disconnect 444',
badReq: 'Parameter error 400',
forbidden: 'Access Forbidden 403',
serverErr: 'Server error 500',
resHtml: 'Response page',
allowHelper: 'Allowing access will skip subsequent WAF rules, please use with caution',
captcha: 'human-machine verification',
fiveSeconds: '5 seconds verification',
location: 'Region',
redisConfig: 'Redis configuration',
redisHelper: 'Enable Redis to persist temporarily blocked IPs',
wafHelper: 'All websites will lose protection after closing',
},
monitor: {
name: 'Website Monitor',

View file

@ -2094,6 +2094,35 @@ const message = {
javaFileter: 'Java 危險檔案過濾',
scannerFilter: '掃描器過濾',
escapeFilter: '轉義過濾',
customRule: '自訂規則',
httpMethod: 'HTTP 方法過濾',
fileExt: '檔案上傳限制',
fileExtHelper: '禁止上傳的檔案副檔名',
deny: '禁止',
allow: '只允許',
field: '匹配對象',
pattern: '符合條件',
ruleContent: '符合內容',
contain: '包含',
equal: '等於',
regex: '正規表示式',
notEqual: '不等於',
customRuleHelper: '根據條件匹配執行對應動作',
actionAllow: '允許',
blockIP: '封鎖 IP',
code: '返回狀態碼',
noRes: '斷開連線 444',
badReq: '參數錯誤 400',
forbidden: '禁止訪問 403',
serverErr: '伺服器錯誤 500',
resHtml: '回應頁面',
allowHelper: '允許訪問會跳過後續的 WAF 規則請謹慎使用',
captcha: '人機驗證',
fiveSeconds: '5 秒驗證',
location: '地區',
redisConfig: 'Redis 配置',
redisHelper: '開啟 Redis 可以將暫時拉黑的 IP 持久化',
wafHelper: '關閉之後所有網站將失去防護',
},
monitor: {
name: '網站監控',

View file

@ -2011,6 +2011,7 @@ const message = {
},
xpack: {
name: '专业版',
menu: '高级功能',
waf: {
name: 'WAF',
blackWhite: '黑白名单',
@ -2065,7 +2066,7 @@ const message = {
cookieHelper: '禁止请求中携带恶意 Cookie',
headerDefense: 'Header 规则',
headerHelper: '禁止请求中携带恶意 Header',
httpRule: 'HTTP 请求方法规则',
httpRule: 'HTTP 规则',
httpHelper: '限制网站的请求方法类型',
geoRule: '地区访问限制',
geoHelper: '限制某些地区访问你的网站',
@ -2094,6 +2095,35 @@ const message = {
javaFileter: 'Java 危险文件过滤',
scannerFilter: '扫描器过滤',
escapeFilter: '转义过滤',
customRule: '自定义规则',
httpMethod: 'HTTP 方法过滤',
fileExt: '文件上传限制',
fileExtHelper: '禁止上传的文件扩展名',
deny: '禁止',
allow: '仅允许',
field: '匹配对象',
pattern: '匹配条件',
ruleContent: '匹配内容',
contain: '包含',
equal: '等于',
regex: '正则表达式',
notEqual: '不等于',
customRuleHelper: '根据条件匹配执行相应动作',
actionAllow: '允许',
blockIP: '封禁 IP',
code: '返回状态码',
noRes: '断开连接 444',
badReq: '参数错误 400',
forbidden: '禁止访问 403',
serverErr: '服务器错误 500',
resHtml: '响应页面',
allowHelper: '允许访问会跳过后续的 WAF 规则请谨慎使用',
captcha: '人机验证',
fiveSeconds: '5 秒验证',
location: '地区',
redisConfig: 'Redis 配置',
redisHelper: '开启 Redis 可以将临时拉黑的 IP 持久化',
wafHelper: '关闭之后所有网站将失去防护',
},
monitor: {
name: '网站监控',

View file

@ -90,7 +90,7 @@
<script setup lang="ts">
import { onMounted, onUnmounted, reactive, ref } from 'vue';
import { Runtime } from '@/api/interface/runtime';
import { OperateRuntime, SearchRuntimes } from '@/api/modules/runtime';
import { OperateRuntime, SearchRuntimes, SyncRuntime } from '@/api/modules/runtime';
import { dateFormat } from '@/utils/util';
import OperateNode from '@/views/website/runtime/node/operate/index.vue';
import Status from '@/components/status/index.vue';
@ -192,6 +192,10 @@ const search = async () => {
}
};
const sync = () => {
SyncRuntime();
};
const openModules = (row: Runtime.Runtime) => {
moduleRef.value.acceptParams({ id: row.id, packageManager: row.params['PACKAGE_MANAGER'] });
};
@ -243,10 +247,12 @@ const toFolder = (folder: string) => {
};
onMounted(() => {
sync();
search();
timer = setInterval(() => {
search();
}, 10000 * 3);
sync();
}, 1000 * 10);
});
onUnmounted(() => {