fix: check.sh — не падать до docker compose, проверка после старта

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
shop
2026-05-16 17:38:35 +03:00
parent 5c1be7da21
commit b6d97f8a73
6 changed files with 151 additions and 36 deletions
+5 -5
View File
@@ -25,17 +25,17 @@ cd shop3
chmod +x install.sh check.sh chmod +x install.sh check.sh
./install.sh ./install.sh
# 3. Проверка версий # 3. Запуск
./check.sh
# 4. Запуск
docker compose up --build -d docker compose up --build -d
# 4. Проверка (после старта контейнеров)
./check.sh --after-start
``` ```
Одной цепочкой (после клона введите ответы установщика): Одной цепочкой (после клона введите ответы установщика):
```bash ```bash
git clone https://git.evilfox.cc/test/shop3.git && cd shop3 && chmod +x install.sh check.sh && ./install.sh && ./check.sh && docker compose up --build -d git clone https://git.evilfox.cc/test/shop3.git && cd shop3 && chmod +x install.sh check.sh && ./install.sh && docker compose up --build -d && ./check.sh --after-start
``` ```
С Go на сервере вместо `install.sh`: С Go на сервере вместо `install.sh`:
+13 -2
View File
@@ -1,4 +1,15 @@
# Проверка версий: Go, Docker, PostgreSQL # Проверка версий (до или после docker compose)
param([switch]$AfterStart)
$ErrorActionPreference = "Stop" $ErrorActionPreference = "Stop"
Set-Location $PSScriptRoot Set-Location $PSScriptRoot
go run ./cmd/check
if ($AfterStart) {
& "$PSScriptRoot\check.sh" --after-start
} else {
& bash "$PSScriptRoot\check.sh" 2>$null
if ($LASTEXITCODE -ne 0) {
$env:CHECK_SKIP_DB = "1"
go run ./cmd/check
}
}
Regular → Executable
+64 -5
View File
@@ -1,8 +1,67 @@
#!/bin/sh #!/bin/sh
set -e set -e
cd "$(dirname "$0")" cd "$(dirname "$0")"
if command -v go >/dev/null 2>&1; then
go run ./cmd/check MODE="${1:-pre}"
else
docker run --rm -v "$(pwd):/app" -w /app golang:1.22-alpine go run ./cmd/check host_docker_check() {
fi if command -v docker >/dev/null 2>&1; then
if docker version >/dev/null 2>&1; then
echo " ✓ docker: $(docker version --format '{{.Server.Version}}' 2>/dev/null || docker --version)"
else
echo " ! docker: установлен, но демон недоступен (запустите docker)"
fi
if docker compose version >/dev/null 2>&1; then
echo " ✓ docker_compose: $(docker compose version --short 2>/dev/null || docker compose version)"
else
echo " ! docker_compose: не найден"
fi
else
echo " ! docker: не найден на хосте"
echo " ! docker_compose: не найден на хосте"
fi
}
run_go_check() {
if command -v go >/dev/null 2>&1; then
CHECK_HOST_TOOLS=1 "$@" go run ./cmd/check
else
CHECK_HOST_TOOLS=0 "$@" docker run --rm -v "$(pwd):/app" -w /app golang:1.22-alpine go run ./cmd/check
fi
}
post_start_check() {
echo "=== Проверка после запуска ==="
host_docker_check
echo ""
if docker compose ps 2>/dev/null | grep -qE 'shop-app|running'; then
if docker compose exec -T app wget -qO- http://127.0.0.1:8080/health 2>/dev/null; then
echo ""
echo " ✓ app /health: OK"
fi
elif command -v curl >/dev/null 2>&1; then
if curl -sf "http://127.0.0.1:${HTTP_PORT:-80}/health" 2>/dev/null; then
echo ""
echo " ✓ /health: OK"
else
echo " ✗ /health: сервис не отвечает — проверьте: docker compose ps"
exit 1
fi
fi
CHECK_SKIP_DB=0 CHECK_HOST_TOOLS=1 run_go_check
}
case "$MODE" in
--after-start|post)
post_start_check
;;
*)
echo "=== Проверка перед запуском (БД будет проверена после docker compose) ==="
host_docker_check
echo ""
CHECK_SKIP_DB=1 run_go_check
echo ""
echo "Далее: docker compose up --build -d"
echo "Затем: ./check.sh --after-start"
;;
esac
+63 -19
View File
@@ -4,8 +4,10 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"net/url"
"os" "os"
"path/filepath" "path/filepath"
"strings"
"github.com/jackc/pgx/v5/pgxpool" "github.com/jackc/pgx/v5/pgxpool"
@@ -15,38 +17,30 @@ import (
func main() { func main() {
loadDotEnv() loadDotEnv()
skipDB := os.Getenv("CHECK_SKIP_DB") == "1"
hostTools := os.Getenv("CHECK_HOST_TOOLS") != "0"
ctx := context.Background() ctx := context.Background()
report := check.AppInfo() report := check.AppInfo()
if hostTools {
report.Items = append(report.Items, check.ToolVersions(ctx)...) report.Items = append(report.Items, check.ToolVersions(ctx)...)
}
dbURL := os.Getenv("DATABASE_URL") dbURL := os.Getenv("DATABASE_URL")
if dbURL == "" { if skipDB {
report.Items = append(report.Items, check.Item{ report.Items = append(report.Items, check.Item{
Name: "database", Name: "database",
Status: check.StatusWarn, Status: check.StatusWarn,
Detail: "DATABASE_URL не задан — запустите: go run ./cmd/install", Detail: "проверка отложена — сначала выполните: docker compose up -d, затем ./check.sh --after-start",
}) })
} else { } else if dbURL == "" {
pool, err := pgxpool.New(ctx, dbURL)
if err != nil {
report.Items = append(report.Items, check.Item{ report.Items = append(report.Items, check.Item{
Name: "database", Name: "database",
Status: check.StatusError, Status: check.StatusWarn,
Detail: err.Error(), Detail: "DATABASE_URL не задан — запустите: ./install.sh",
}) })
} else { } else {
defer pool.Close() appendDBChecks(ctx, &report, dbURL)
dbItems, err := check.Database(ctx, pool)
if err != nil {
report.Items = append(report.Items, check.Item{
Name: "database",
Status: check.StatusError,
Detail: err.Error(),
})
} else {
report.Items = append(report.Items, dbItems...)
}
}
} }
enc := json.NewEncoder(os.Stdout) enc := json.NewEncoder(os.Stdout)
@@ -61,6 +55,56 @@ func main() {
} }
} }
func appendDBChecks(ctx context.Context, report *check.Report, dbURL string) {
pool, err := pgxpool.New(ctx, dbURL)
if err != nil {
report.Items = append(report.Items, dbCheckItem(err, dbURL))
return
}
defer pool.Close()
dbItems, err := check.Database(ctx, pool)
if err != nil {
report.Items = append(report.Items, check.Item{
Name: "database",
Status: dbCheckStatus(err, dbURL),
Detail: err.Error(),
})
return
}
report.Items = append(report.Items, dbItems...)
}
func dbCheckItem(err error, dbURL string) check.Item {
return check.Item{
Name: "database",
Status: dbCheckStatus(err, dbURL),
Detail: err.Error(),
}
}
func dbCheckStatus(err error, dbURL string) check.Status {
if err == nil {
return check.StatusOK
}
msg := strings.ToLower(err.Error())
if isDockerInternalHost(dbURL) && (strings.Contains(msg, "no such host") ||
strings.Contains(msg, "name or service not known") ||
strings.Contains(msg, "hostname resolving")) {
return check.StatusWarn
}
return check.StatusError
}
func isDockerInternalHost(dbURL string) bool {
u, err := url.Parse(dbURL)
if err != nil {
return false
}
host := u.Hostname()
return host == "postgres" || host == "db" || host == "shop-postgres"
}
func printSummary(r check.Report) { func printSummary(r check.Report) {
fmt.Printf("ShopNova %s | %s\n\n", r.AppVersion, r.GoVersion) fmt.Printf("ShopNova %s | %s\n\n", r.AppVersion, r.GoVersion)
for _, it := range r.Items { for _, it := range r.Items {
Regular → Executable
View File
+2 -1
View File
@@ -59,8 +59,9 @@ func RunInteractive(root string) (Config, error) {
} }
fmt.Println("\n✓ Созданы файлы: .env, caddy/Caddyfile") fmt.Println("\n✓ Созданы файлы: .env, caddy/Caddyfile")
fmt.Println("\nДальше:") fmt.Println("\nДальше (на сервере):")
fmt.Println(" docker compose up --build -d") fmt.Println(" docker compose up --build -d")
fmt.Println(" ./check.sh --after-start")
if !useLocalDomain(cfg.SiteDomain) { if !useLocalDomain(cfg.SiteDomain) {
fmt.Printf(" Сайт: https://%s\n", cfg.SiteDomain) fmt.Printf(" Сайт: https://%s\n", cfg.SiteDomain)
} else { } else {