mirror of
https://github.com/hansjone/netx.git
synced 2026-10-09 14:10:44 +08:00
Scale biz_state collects with dedicated workers and non-blocking UI poll.
Add PG claim/NE mutex, persist pool, and biz_state_worker replicas; fix double-SSH and row-count bugs; stop 32m collectNow while-loop from freezing page switches. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
0eb65a839e
commit
3a0de0d7fb
22 changed files with 1210 additions and 165 deletions
|
|
@ -34,6 +34,7 @@ $errFile = Join-Path $runDir "netx.err.log"
|
|||
$workerPidFile = Join-Path $runDir "worker.pid"
|
||||
$workerLogFile = Join-Path $runDir "worker.out.log"
|
||||
$workerErrFile = Join-Path $runDir "worker.err.log"
|
||||
$bizStateWorkerPidDir = Join-Path $runDir "biz_state_workers"
|
||||
$webPidFile = Join-Path $runDir "web.pid"
|
||||
$webLogFile = Join-Path $runDir "web.out.log"
|
||||
$webErrFile = Join-Path $runDir "web.err.log"
|
||||
|
|
@ -187,6 +188,41 @@ function Start-NetxWorker {
|
|||
}
|
||||
}
|
||||
|
||||
function Start-BizStateWorkers {
|
||||
if ($InlineSchedulers) {
|
||||
return
|
||||
}
|
||||
$replicas = 2
|
||||
if ($env:NETX_BIZ_STATE_WORKER_REPLICAS) {
|
||||
try { $replicas = [int]$env:NETX_BIZ_STATE_WORKER_REPLICAS } catch { $replicas = 2 }
|
||||
}
|
||||
if ($replicas -lt 1) { $replicas = 1 }
|
||||
if (-not (Test-Path $bizStateWorkerPidDir)) {
|
||||
New-Item -ItemType Directory -Path $bizStateWorkerPidDir | Out-Null
|
||||
}
|
||||
Write-Host "==> Starting biz_state workers (replicas=$replicas)"
|
||||
for ($i = 0; $i -lt $replicas; $i++) {
|
||||
$outLog = Reset-LogFile -Path (Join-Path $bizStateWorkerPidDir "worker$i.out.log")
|
||||
$errLog = Reset-LogFile -Path (Join-Path $bizStateWorkerPidDir "worker$i.err.log")
|
||||
$pidPath = Join-Path $bizStateWorkerPidDir "worker$i.pid"
|
||||
$proc = Start-Process -FilePath $pythonExe `
|
||||
-ArgumentList @("-m", "netx_api.biz_state_worker") `
|
||||
-WorkingDirectory $projectRoot `
|
||||
-WindowStyle Hidden `
|
||||
-RedirectStandardOutput $outLog `
|
||||
-RedirectStandardError $errLog `
|
||||
-PassThru
|
||||
Set-Content -Path $pidPath -Value "$($proc.Id)"
|
||||
Write-Host "biz_state_worker[$i] PID=$($proc.Id)"
|
||||
Start-Sleep -Milliseconds 400
|
||||
if ($proc.HasExited) {
|
||||
Write-Host "[ERR] biz_state_worker[$i] exited immediately." -ForegroundColor Red
|
||||
Show-LogTail -Path $errLog
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($Background) {
|
||||
# Truncate logs so a failed start is not confused with an old run.
|
||||
Set-Content -Path $logFile -Value "" -Encoding utf8
|
||||
|
|
@ -226,6 +262,7 @@ if ($Background) {
|
|||
}
|
||||
Write-Host "==> netx API ready: http://${BindHost}:${Port}/health" -ForegroundColor Green
|
||||
Start-NetxWorker
|
||||
Start-BizStateWorkers
|
||||
if ($WithWeb) {
|
||||
Write-Host "==> Starting Vite dev server in background"
|
||||
$webRoot = Join-Path $projectRoot "web"
|
||||
|
|
@ -283,5 +320,6 @@ if ($WithWeb) {
|
|||
}
|
||||
|
||||
Start-NetxWorker
|
||||
Start-BizStateWorkers
|
||||
Write-Host "==> Starting netx API in foreground"
|
||||
& $pythonExe -m netx_api.main
|
||||
|
|
|
|||
|
|
@ -239,6 +239,21 @@ if [[ "${INLINE_SCHEDULERS}" != "1" ]]; then
|
|||
echo "PID = ${WORKER_PID}"
|
||||
echo "Log = ${WORKER_LOG_FILE}"
|
||||
echo "Err = ${WORKER_ERR_FILE}"
|
||||
|
||||
REPLICAS="${NETX_BIZ_STATE_WORKER_REPLICAS:-2}"
|
||||
if [[ "${REPLICAS}" -lt 1 ]]; then REPLICAS=1; fi
|
||||
BIZ_DIR="${RUN_DIR}/biz_state_workers"
|
||||
mkdir -p "${BIZ_DIR}"
|
||||
echo "==> Starting biz_state workers (replicas=${REPLICAS})"
|
||||
for ((i=0; i<REPLICAS; i++)); do
|
||||
(
|
||||
cd "${ROOT_DIR}"
|
||||
nohup "${PYTHON_CMD}" -m netx_api.biz_state_worker \
|
||||
>"${BIZ_DIR}/worker${i}.out.log" 2>"${BIZ_DIR}/worker${i}.err.log" &
|
||||
echo $! > "${BIZ_DIR}/worker${i}.pid"
|
||||
)
|
||||
echo "biz_state_worker[${i}] PID=$(cat "${BIZ_DIR}/worker${i}.pid")"
|
||||
done
|
||||
fi
|
||||
|
||||
if [[ "${API_ONLY}" != "1" ]]; then
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ $runDir = Join-Path $PSScriptRoot ".run"
|
|||
$pidFile = Join-Path $runDir "netx.pid"
|
||||
$workerPidFile = Join-Path $runDir "worker.pid"
|
||||
$webPidFile = Join-Path $runDir "web.pid"
|
||||
$bizStateWorkerPidDir = Join-Path $runDir "biz_state_workers"
|
||||
|
||||
function Stop-OnePid {
|
||||
param([int]$ProcId, [string]$Label)
|
||||
|
|
@ -62,13 +63,19 @@ function Get-ListenPids {
|
|||
function Stop-NetxByCommandLine {
|
||||
# Orphan workers often have no worker.pid but still hold worker.out.log.
|
||||
$hits = @(Get-CimInstance Win32_Process -ErrorAction SilentlyContinue |
|
||||
Where-Object { $_.CommandLine -match 'netx_api\.(main|worker)' })
|
||||
Where-Object { $_.CommandLine -match 'netx_api\.(main|worker|biz_state_worker)' })
|
||||
if ($hits.Count -eq 0) {
|
||||
Write-Host "[INFO] No netx_api.main/worker process by command line"
|
||||
Write-Host "[INFO] No netx_api.main/worker/biz_state_worker process by command line"
|
||||
return
|
||||
}
|
||||
foreach ($p in $hits) {
|
||||
$kind = if ($p.CommandLine -match 'netx_api\.worker') { "worker(cmd)" } else { "api(cmd)" }
|
||||
$kind = if ($p.CommandLine -match 'biz_state_worker') {
|
||||
"biz_state_worker(cmd)"
|
||||
} elseif ($p.CommandLine -match 'netx_api\.worker') {
|
||||
"worker(cmd)"
|
||||
} else {
|
||||
"api(cmd)"
|
||||
}
|
||||
Stop-OnePid -ProcId ([int]$p.ProcessId) -Label $kind
|
||||
}
|
||||
}
|
||||
|
|
@ -99,6 +106,18 @@ if (Test-Path $workerPidFile) {
|
|||
Write-Host "[INFO] No worker PID file"
|
||||
}
|
||||
|
||||
if (Test-Path $bizStateWorkerPidDir) {
|
||||
Get-ChildItem -Path $bizStateWorkerPidDir -Filter "*.pid" -ErrorAction SilentlyContinue | ForEach-Object {
|
||||
$t = (Get-Content -Path $_.FullName -ErrorAction SilentlyContinue | Select-Object -First 1)
|
||||
$id = 0
|
||||
[void][int]::TryParse("$t", [ref]$id)
|
||||
if ($id -gt 0) {
|
||||
Stop-OnePid -ProcId $id -Label "biz_state_worker"
|
||||
}
|
||||
Remove-Item -Path $_.FullName -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
}
|
||||
|
||||
if (Test-Path $webPidFile) {
|
||||
$webPidText = (Get-Content -Path $webPidFile -ErrorAction SilentlyContinue | Select-Object -First 1)
|
||||
$webProcId = 0
|
||||
|
|
|
|||
|
|
@ -102,6 +102,16 @@ else
|
|||
echo "[INFO] No worker PID file: ${WORKER_PID_FILE}"
|
||||
fi
|
||||
|
||||
BIZ_DIR="${RUN_DIR}/biz_state_workers"
|
||||
if [[ -d "${BIZ_DIR}" ]]; then
|
||||
for f in "${BIZ_DIR}"/*.pid; do
|
||||
[[ -f "${f}" ]] || continue
|
||||
BPID="$(head -n 1 "${f}" | tr -d '[:space:]' || true)"
|
||||
kill_pid "${BPID}" "biz_state_worker"
|
||||
rm -f "${f}" || true
|
||||
done
|
||||
fi
|
||||
|
||||
if [[ -f "${WEB_PID_FILE}" ]]; then
|
||||
WEB_PID="$(head -n 1 "${WEB_PID_FILE}" | tr -d '[:space:]' || true)"
|
||||
kill_pid "${WEB_PID}" "web"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue