From b6def0f25b40f097b9adbfc1125db93e3b5b6633 Mon Sep 17 00:00:00 2001 From: john Date: Mon, 6 Jul 2026 16:57:38 +0800 Subject: [PATCH] =?UTF-8?q?fix(ops):=20=E8=87=AA=E6=84=88=20goosed=20?= =?UTF-8?q?=E4=BC=9A=E8=AF=9D=20PostgreSQL=EF=BC=8C=E9=98=B2=E6=AD=A2=20H5?= =?UTF-8?q?=20=E5=8D=A1=E5=9C=A8=E5=88=9B=E5=BB=BA=E6=96=B0=E5=AF=B9?= =?UTF-8?q?=E8=AF=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 103 Colima goosed 依赖宿主机 postgresql@17;库停止时 /agent/start 会 pool timeout 约 60s。新增 ensure 脚本、接入监控与发布前检查,并补充拓扑文档。 Co-authored-by: Cursor --- docs/103-runtime-topology.md | 10 +++++++++ scripts/ensure-goose-session-postgres.sh | 28 ++++++++++++++++++++++++ scripts/monitor-goosed-fds.mjs | 25 +++++++++++++++++++++ scripts/release-portal-runtime-prod.sh | 11 ++++++++++ 4 files changed, 74 insertions(+) create mode 100755 scripts/ensure-goose-session-postgres.sh diff --git a/docs/103-runtime-topology.md b/docs/103-runtime-topology.md index c609fc1..5ed1a94 100644 --- a/docs/103-runtime-topology.md +++ b/docs/103-runtime-topology.md @@ -59,6 +59,16 @@ Portal must be released as a runtime artifact. Do not edit source directly on 10 | Compose env | `/Users/john/Project/goosed-prod/.env` | | Image pattern | `tkmind/goosed:prod-${GOOSED_TAG}` | | Session store | PostgreSQL `memind_sessions` through `GOOSE_SESSION_DB_URL` | +| Session PostgreSQL | **Host** `postgresql@17` on `127.0.0.1:5432` (`/opt/homebrew/var/postgresql@17`) | + +**Critical:** Colima goosed reaches the session DB via `host.docker.internal:5432`. If host PostgreSQL is stopped, H5 `/agent/start` hangs ~60s then fails with `pool timed out`, and the UI stays on「正在创建新对话…」. Recovery: + +```bash +ssh john@58.38.22.103 'bash /Users/john/Project/Memind/scripts/ensure-goose-session-postgres.sh' +ssh john@58.38.22.103 '/opt/homebrew/opt/postgresql@17/bin/pg_isready -h 127.0.0.1 -p 5432' +``` + +`cn.tkmind.goosed-monitor`(103)运行 `goosed-prod/scripts/monitor-goosed-containers.mjs`,本地 native goosed 监控用 `scripts/monitor-goosed-fds.mjs`;两者都会在巡检时调用 `ensure-goose-session-postgres.sh`。 Container layout: diff --git a/scripts/ensure-goose-session-postgres.sh b/scripts/ensure-goose-session-postgres.sh new file mode 100755 index 0000000..fcf907a --- /dev/null +++ b/scripts/ensure-goose-session-postgres.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +set -euo pipefail + +# 103 Colima goosed 通过 host.docker.internal:5432 访问本机 PostgreSQL。 +# 该库停止时,/agent/start 会在约 60s 后返回 pool timeout,H5 会卡在「正在创建新对话…」。 +export PATH="/opt/homebrew/bin:/opt/homebrew/opt/postgresql@17/bin:${PATH:-/usr/bin:/bin}" + +PGDATA="${GOOSE_SESSION_PGDATA:-/opt/homebrew/var/postgresql@17}" +PG_LOG="${GOOSE_SESSION_PG_LOG:-${HOME}/Library/Logs/postgresql@17.log}" +PG_HOST="${GOOSE_SESSION_PG_HOST:-127.0.0.1}" +PG_PORT="${GOOSE_SESSION_PG_PORT:-5432}" + +if pg_isready -h "${PG_HOST}" -p "${PG_PORT}" -q 2>/dev/null; then + exit 0 +fi + +echo "$(date -u +%Y-%m-%dT%H:%M:%SZ) goose session postgres not ready; starting (${PGDATA})" +mkdir -p "$(dirname "${PG_LOG}")" +pg_ctl -D "${PGDATA}" -l "${PG_LOG}" start 2>/dev/null || true +sleep 2 + +if pg_isready -h "${PG_HOST}" -p "${PG_PORT}" -q 2>/dev/null; then + echo "$(date -u +%Y-%m-%dT%H:%M:%SZ) goose session postgres ready" + exit 0 +fi + +echo "$(date -u +%Y-%m-%dT%H:%M:%SZ) goose session postgres still down (${PG_HOST}:${PG_PORT})" >&2 +exit 1 diff --git a/scripts/monitor-goosed-fds.mjs b/scripts/monitor-goosed-fds.mjs index 4a09784..cf4b9a3 100755 --- a/scripts/monitor-goosed-fds.mjs +++ b/scripts/monitor-goosed-fds.mjs @@ -1,5 +1,10 @@ #!/usr/bin/env node import { execFileSync, spawnSync } from 'node:child_process'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const ENSURE_GOOSE_SESSION_POSTGRES = path.join(__dirname, 'ensure-goose-session-postgres.sh'); const DRY_RUN = process.argv.includes('--dry-run'); const FD_WARN = Number(process.env.GOOSED_FD_WARN ?? 180); @@ -122,5 +127,25 @@ function monitorGoosed() { } } +function ensureGooseSessionPostgres() { + try { + const result = spawnSync('/bin/bash', [ENSURE_GOOSE_SESSION_POSTGRES], { + encoding: 'utf8', + stdio: ['ignore', 'pipe', 'pipe'], + }); + const output = `${result.stdout ?? ''}${result.stderr ?? ''}`.trim(); + if (output) console.log(output); + if (result.status !== 0) { + console.warn('goose session postgres ensure failed'); + } + } catch (err) { + console.warn( + 'goose session postgres ensure skipped:', + err instanceof Error ? err.message : err, + ); + } +} + +ensureGooseSessionPostgres(); cleanupSandboxProcesses(); monitorGoosed(); diff --git a/scripts/release-portal-runtime-prod.sh b/scripts/release-portal-runtime-prod.sh index 26ebe29..464f0b9 100755 --- a/scripts/release-portal-runtime-prod.sh +++ b/scripts/release-portal-runtime-prod.sh @@ -201,6 +201,17 @@ set -euo pipefail missing=0 +pg_isready_bin="/opt/homebrew/opt/postgresql@17/bin/pg_isready" +if [[ -x "${pg_isready_bin}" ]]; then + if ! "${pg_isready_bin}" -h 127.0.0.1 -p 5432 -q 2>/dev/null; then + echo "goosed dependency check failed: host PostgreSQL (127.0.0.1:5432) is not accepting connections" >&2 + echo "Run: bash /Users/john/Project/Memind/scripts/ensure-goose-session-postgres.sh" >&2 + missing=1 + fi +else + echo "goosed dependency check warning: pg_isready not found; skipping PostgreSQL readiness check" >&2 +fi + docker_bin="/opt/homebrew/bin/docker" if [[ -x "${docker_bin}" ]] && "${docker_bin}" ps --format '{{.Names}}' 2>/dev/null | grep -q '^goosed-prod-1$'; then for index in 1 2 3 4; do