Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f7722be539 | |||
| 779f42c98c | |||
| 525620b0f8 |
@@ -71,13 +71,10 @@ def _get_listening_ports():
|
|||||||
port = int(port_match.group(1))
|
port = int(port_match.group(1))
|
||||||
|
|
||||||
pid_match = re.search(r'pid=(\d+)', line)
|
pid_match = re.search(r'pid=(\d+)', line)
|
||||||
if not pid_match:
|
pid = int(pid_match.group(1)) if pid_match else None
|
||||||
continue
|
|
||||||
pid = int(pid_match.group(1))
|
|
||||||
|
|
||||||
# 提取进程名
|
|
||||||
proc_match = re.search(r'users:\(\(\"([^\"]+)\"', line)
|
proc_match = re.search(r'users:\(\(\"([^\"]+)\"', line)
|
||||||
proc_name = proc_match.group(1) if proc_match else 'unknown'
|
proc_name = proc_match.group(1) if proc_match else '未知进程'
|
||||||
|
|
||||||
services.append({
|
services.append({
|
||||||
'port': port,
|
'port': port,
|
||||||
@@ -219,10 +216,16 @@ def register_discovery_routes(app):
|
|||||||
continue
|
continue
|
||||||
seen_ports.add(port)
|
seen_ports.add(port)
|
||||||
|
|
||||||
cmdline = _get_process_cmdline(pid)
|
if pid:
|
||||||
cwd = _get_process_cwd(pid)
|
cmdline = _get_process_cmdline(pid)
|
||||||
name = _guess_service_name(pid, svc['process'], cmdline)
|
cwd = _get_process_cwd(pid)
|
||||||
svc_type = _guess_service_type(cmdline)
|
name = _guess_service_name(pid, svc['process'], cmdline)
|
||||||
|
svc_type = _guess_service_type(cmdline)
|
||||||
|
else:
|
||||||
|
cmdline = ''
|
||||||
|
cwd = ''
|
||||||
|
name = svc['process']
|
||||||
|
svc_type = 'unknown'
|
||||||
|
|
||||||
undiscovered.append({
|
undiscovered.append({
|
||||||
'port': port,
|
'port': port,
|
||||||
|
|||||||
@@ -929,6 +929,7 @@
|
|||||||
// Tab 切换
|
// Tab 切换
|
||||||
// 系统资源监控变量(必须先声明)
|
// 系统资源监控变量(必须先声明)
|
||||||
let realtimeTimer = null;
|
let realtimeTimer = null;
|
||||||
|
let systemRefreshTimer = null;
|
||||||
let realtimeInterval = 2; // 秒
|
let realtimeInterval = 2; // 秒
|
||||||
let lastAlertTime = 0; // 上次警告时间
|
let lastAlertTime = 0; // 上次警告时间
|
||||||
let thresholds = { cpu: 80, cpu_temp: 80, memory: 85, disk: 90, interval: 60 };
|
let thresholds = { cpu: 80, cpu_temp: 80, memory: 85, disk: 90, interval: 60 };
|
||||||
@@ -957,6 +958,12 @@
|
|||||||
document.getElementById('processListSection').classList.add('hidden');
|
document.getElementById('processListSection').classList.add('hidden');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 离开系统Tab时关闭非实时刷新定时器
|
||||||
|
if (tab !== 'system' && systemRefreshTimer) {
|
||||||
|
clearInterval(systemRefreshTimer);
|
||||||
|
systemRefreshTimer = null;
|
||||||
|
}
|
||||||
|
|
||||||
if (tab === 'cron') {
|
if (tab === 'cron') {
|
||||||
loadCronTasks();
|
loadCronTasks();
|
||||||
}
|
}
|
||||||
@@ -965,6 +972,8 @@
|
|||||||
loadDesktopNotifySetting();
|
loadDesktopNotifySetting();
|
||||||
renderEmailRules();
|
renderEmailRules();
|
||||||
loadSystemStats();
|
loadSystemStats();
|
||||||
|
// 启动系统资源定时刷新(按页面刷新间隔)
|
||||||
|
startSystemRefresh();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1281,14 +1290,17 @@
|
|||||||
const toggle = document.getElementById('realtimeToggle');
|
const toggle = document.getElementById('realtimeToggle');
|
||||||
const indicator = document.getElementById('realtimeIndicator');
|
const indicator = document.getElementById('realtimeIndicator');
|
||||||
|
|
||||||
|
// 先停止系统定时刷新
|
||||||
|
if (systemRefreshTimer) {
|
||||||
|
clearInterval(systemRefreshTimer);
|
||||||
|
systemRefreshTimer = null;
|
||||||
|
}
|
||||||
|
|
||||||
if (checked) {
|
if (checked) {
|
||||||
toggle.classList.add('active');
|
toggle.classList.add('active');
|
||||||
indicator.classList.remove('hidden');
|
indicator.classList.remove('hidden');
|
||||||
// 立即加载一次
|
|
||||||
loadSystemStats();
|
loadSystemStats();
|
||||||
// 启动定时器
|
|
||||||
realtimeTimer = setInterval(loadSystemStats, realtimeInterval * 1000);
|
realtimeTimer = setInterval(loadSystemStats, realtimeInterval * 1000);
|
||||||
// 如果进程列表开关也开启,则显示并加载
|
|
||||||
if (document.getElementById('showProcessListCheck').checked) {
|
if (document.getElementById('showProcessListCheck').checked) {
|
||||||
document.getElementById('processListSection').classList.remove('hidden');
|
document.getElementById('processListSection').classList.remove('hidden');
|
||||||
loadTopProcesses();
|
loadTopProcesses();
|
||||||
@@ -1297,14 +1309,28 @@
|
|||||||
toggle.classList.remove('active');
|
toggle.classList.remove('active');
|
||||||
indicator.classList.add('hidden');
|
indicator.classList.add('hidden');
|
||||||
document.getElementById('processListSection').classList.add('hidden');
|
document.getElementById('processListSection').classList.add('hidden');
|
||||||
// 停止定时器
|
|
||||||
if (realtimeTimer) {
|
if (realtimeTimer) {
|
||||||
clearInterval(realtimeTimer);
|
clearInterval(realtimeTimer);
|
||||||
realtimeTimer = null;
|
realtimeTimer = null;
|
||||||
}
|
}
|
||||||
|
// 关闭实时后,按页面刷新间隔继续刷新系统资源
|
||||||
|
startSystemRefresh();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function startSystemRefresh() {
|
||||||
|
// 先停掉旧定时器
|
||||||
|
if (systemRefreshTimer) {
|
||||||
|
clearInterval(systemRefreshTimer);
|
||||||
|
systemRefreshTimer = null;
|
||||||
|
}
|
||||||
|
// 如果在实时监控模式则不启动(由realtimeTimer负责)
|
||||||
|
if (document.getElementById('realtimeCheck').checked) return;
|
||||||
|
// 按页面刷新间隔定时刷新
|
||||||
|
const intervalSec = parseInt(document.getElementById('refreshInterval').value) || 30;
|
||||||
|
systemRefreshTimer = setInterval(loadSystemStats, intervalSec * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
function toggleProcessList() {
|
function toggleProcessList() {
|
||||||
const checked = document.getElementById('showProcessListCheck').checked;
|
const checked = document.getElementById('showProcessListCheck').checked;
|
||||||
const realtimeChecked = document.getElementById('realtimeCheck').checked;
|
const realtimeChecked = document.getElementById('realtimeCheck').checked;
|
||||||
@@ -2238,6 +2264,7 @@
|
|||||||
const newService = {
|
const newService = {
|
||||||
id: 'custom_' + Date.now(),
|
id: 'custom_' + Date.now(),
|
||||||
name: name,
|
name: name,
|
||||||
|
port: port || '',
|
||||||
url: mainUrl,
|
url: mainUrl,
|
||||||
admin_url: adminUrl || null,
|
admin_url: adminUrl || null,
|
||||||
description: desc || '自定义外部服务',
|
description: desc || '自定义外部服务',
|
||||||
@@ -2750,6 +2777,11 @@
|
|||||||
|
|
||||||
clearInterval(refreshTimer);
|
clearInterval(refreshTimer);
|
||||||
refreshTimer = setInterval(() => { if (currentTab === 'projects') loadProjects(); }, seconds * 1000);
|
refreshTimer = setInterval(() => { if (currentTab === 'projects') loadProjects(); }, seconds * 1000);
|
||||||
|
|
||||||
|
// 如果当前在系统Tab且非实时模式,更新系统刷新间隔
|
||||||
|
if (currentTab === 'system' && !document.getElementById('realtimeCheck').checked) {
|
||||||
|
startSystemRefresh();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
@@ -2904,7 +2936,7 @@
|
|||||||
<div class="flex items-center gap-3 flex-1 min-w-0">
|
<div class="flex items-center gap-3 flex-1 min-w-0">
|
||||||
<span class="text-xs text-cyan-400 font-mono">:${s.port}</span>
|
<span class="text-xs text-cyan-400 font-mono">:${s.port}</span>
|
||||||
<span class="text-gray-300 text-sm truncate">${s.suggested_name}</span>
|
<span class="text-gray-300 text-sm truncate">${s.suggested_name}</span>
|
||||||
<span class="text-gray-500 text-xs">PID ${s.pid}</span>
|
<span class="text-gray-500 text-xs">PID ${s.pid != null ? s.pid : '受权限限制'}</span>
|
||||||
<span class="text-gray-500 text-xs truncate hidden md:inline">${(s.cmdline || '').substring(0, 60)}</span>
|
<span class="text-gray-500 text-xs truncate hidden md:inline">${(s.cmdline || '').substring(0, 60)}</span>
|
||||||
</div>
|
</div>
|
||||||
<button onclick="quickAddService(${s.port}, '${s.suggested_name.replace(/'/g, "\\'")}', '${s.suggested_type}', '${(s.cwd || '').replace(/'/g, "\\'")}')" class="btn bg-green-600/50 hover:bg-green-600 px-2 py-1 rounded text-xs shrink-0 ml-2">
|
<button onclick="quickAddService(${s.port}, '${s.suggested_name.replace(/'/g, "\\'")}', '${s.suggested_type}', '${(s.cwd || '').replace(/'/g, "\\'")}')" class="btn bg-green-600/50 hover:bg-green-600 px-2 py-1 rounded text-xs shrink-0 ml-2">
|
||||||
|
|||||||
24
watchdog.sh
Executable file
24
watchdog.sh
Executable file
@@ -0,0 +1,24 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# project-panel 守护脚本 - 进程挂了自动重启
|
||||||
|
SERVICE_DIR="/home/openclaw/.openclaw/workspace-hz4th_coder/works/project-panel"
|
||||||
|
PYTHON="/home/hz1/miniconda3/envs/openclaw/bin/python3.12"
|
||||||
|
PORT=16022
|
||||||
|
LOG="$SERVICE_DIR/logs/watchdog.log"
|
||||||
|
|
||||||
|
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 守护进程启动,监控端口 $PORT" >> "$LOG"
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
if ! ss -tlnp 2>/dev/null | grep -q ":$PORT "; then
|
||||||
|
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 检测到 $PORT 端口离线,重启服务..." >> "$LOG"
|
||||||
|
cd "$SERVICE_DIR"
|
||||||
|
mkdir -p logs
|
||||||
|
nohup "$PYTHON" app.py > logs/app.log 2>&1 &
|
||||||
|
sleep 3
|
||||||
|
if ss -tlnp 2>/dev/null | grep -q ":$PORT "; then
|
||||||
|
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 服务重启成功" >> "$LOG"
|
||||||
|
else
|
||||||
|
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 服务重启失败!" >> "$LOG"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
sleep 10
|
||||||
|
done
|
||||||
Reference in New Issue
Block a user