File size: 6,124 Bytes
e327f0d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# scripts/dev-up.ps1
# ---------------------------------------------------------------------------
# Smoke up + health verification for the local docker compose stack.
#
# Usage (from repo root):
#   pwsh -File scripts/dev-up.ps1
#   pwsh -File scripts/dev-up.ps1 -Rebuild      # force --build
#   pwsh -File scripts/dev-up.ps1 -InfraOnly    # only postgres/redis/minio
#
# What it does:
#   1. Pre-flight: docker daemon, port collisions (5432/6379/9000/9001/8000),
#      ML model snapshot directory.
#   2. docker compose up -d (infra first, then backend + worker).
#   3. Poll health endpoints:
#        - postgres pg_isready
#        - redis PING
#        - minio /minio/health/live
#        - backend http://localhost:8000/health
#   4. Print summary URLs.
# ---------------------------------------------------------------------------
[CmdletBinding()]
param(
    [switch]$Rebuild,
    [switch]$InfraOnly
)

$ErrorActionPreference = "Stop"
$RepoRoot = (Resolve-Path "$PSScriptRoot\..").Path
Push-Location $RepoRoot

function Section($msg) { Write-Host "`n=== $msg ===" -ForegroundColor Cyan }
function OK($msg)      { Write-Host "  ok: $msg" -ForegroundColor Green }
function Warn($msg)    { Write-Host "  warn: $msg" -ForegroundColor Yellow }
function Fail($msg)    { Write-Host "  FAIL: $msg" -ForegroundColor Red }

function Test-Port($port) {
    $listener = $null
    try {
        $listener = [System.Net.Sockets.TcpListener]::new([System.Net.IPAddress]::Loopback, $port)
        $listener.Start()
        return $true   # free
    } catch {
        return $false  # in use
    } finally {
        if ($listener) { $listener.Stop() }
    }
}

# ---------- 1. Pre-flight ----------
Section "Pre-flight checks"

try { docker info --format "{{.ServerVersion}}" | Out-Null; OK "docker daemon reachable" }
catch { Fail "docker daemon not reachable. Start Docker Desktop."; Pop-Location; exit 1 }

$ports = @(5432, 6379, 9000, 9001, 8000)
$collisions = @()
foreach ($p in $ports) {
    if (-not (Test-Port $p)) {
        $collisions += $p
        Warn "port $p is already in use on the host"
    } else {
        OK "port $p free"
    }
}
if ($collisions.Count -gt 0) {
    Warn "Port collisions: $($collisions -join ', '). 'docker compose up' will fail to bind these."
    Warn "Stop the conflicting process or edit docker-compose.yml port mappings."
}

# Model snapshot dir check (override via MODEL_SNAPSHOT_DIR)
$defaultSnapshot = Join-Path $RepoRoot "services\ml\runs\bundles\full_20260515_044630\_SNAPSHOT_FOR_BUILD"
$snapshot = if ($env:MODEL_SNAPSHOT_DIR) { $env:MODEL_SNAPSHOT_DIR } else { $defaultSnapshot }
if (-not (Test-Path $snapshot)) {
    Warn "ML snapshot dir missing: $snapshot"
    # Try fallback: most recent bundle under services/ml/runs/bundles/
    $bundleRoot = Join-Path $RepoRoot "services\ml\runs\bundles"
    if (Test-Path $bundleRoot) {
        $candidate = Get-ChildItem $bundleRoot -Directory -Filter "full_*" |
                     Sort-Object LastWriteTime -Descending |
                     Select-Object -First 1
        if ($candidate) {
            $fallback = Join-Path $candidate.FullName "_SNAPSHOT_FOR_BUILD"
            if (Test-Path $fallback) {
                $env:MODEL_SNAPSHOT_DIR = $fallback
                OK "fallback snapshot dir set: $fallback"
            } else {
                Warn "No _SNAPSHOT_FOR_BUILD under $($candidate.FullName). Backend will start without ML weights."
            }
        }
    }
} else {
    OK "model snapshot dir: $snapshot"
}

# ---------- 2. Compose up ----------
Section "docker compose up (infrastructure)"
$buildFlag = if ($Rebuild) { "--build" } else { "" }

# Infra first so dependencies resolve cleanly.
$infraServices = @("postgres", "redis", "minio", "minio-init")
& docker compose up -d @infraServices
if ($LASTEXITCODE -ne 0) { Fail "docker compose up (infra) failed"; Pop-Location; exit 1 }
OK "infra services started"

if (-not $InfraOnly) {
    Section "docker compose up (backend + worker)"
    $appServices = @("backend", "worker")
    if ($Rebuild) {
        & docker compose up -d --build @appServices
    } else {
        & docker compose up -d @appServices
    }
    if ($LASTEXITCODE -ne 0) { Fail "docker compose up (app) failed"; Pop-Location; exit 1 }
    OK "backend + worker started"
}

# ---------- 3. Health checks ----------
Section "Health checks"

function Wait-For($name, [ScriptBlock]$probe, [int]$timeoutSec = 90) {
    $deadline = (Get-Date).AddSeconds($timeoutSec)
    while ((Get-Date) -lt $deadline) {
        try {
            if (& $probe) { OK "$name healthy"; return $true }
        } catch { }
        Start-Sleep -Seconds 2
    }
    Fail "$name did not become healthy within ${timeoutSec}s"
    return $false
}

$allHealthy = $true

$allHealthy = (Wait-For "postgres" {
    docker exec hasarui-postgres pg_isready -U postgres -d arac_hasar 2>&1 | Out-Null
    $LASTEXITCODE -eq 0
} 60) -and $allHealthy

$allHealthy = (Wait-For "redis" {
    (docker exec hasarui-redis redis-cli ping 2>&1).Trim() -eq "PONG"
} 30) -and $allHealthy

$allHealthy = (Wait-For "minio" {
    try {
        $r = Invoke-WebRequest "http://localhost:9000/minio/health/live" -UseBasicParsing -TimeoutSec 3
        $r.StatusCode -eq 200
    } catch { $false }
} 45) -and $allHealthy

if (-not $InfraOnly) {
    $allHealthy = (Wait-For "backend /health" {
        try {
            $r = Invoke-WebRequest "http://localhost:8000/health" -UseBasicParsing -TimeoutSec 3
            $r.StatusCode -eq 200
        } catch { $false }
    } 180) -and $allHealthy
}

# ---------- 4. Summary ----------
Section "Summary"
docker compose ps
Write-Host ""
Write-Host "URLs:" -ForegroundColor Cyan
Write-Host "  API health   -> http://localhost:8000/health"
Write-Host "  API docs     -> http://localhost:8000/docs"
Write-Host "  MinIO console -> http://localhost:9001  (minioadmin / minioadmin)"
Write-Host "  Postgres     -> postgresql://postgres:postgres@localhost:5432/arac_hasar"
Write-Host ""
Write-Host "Next: pnpm --filter @arac-hasar/web dev   # http://localhost:3000"

Pop-Location
if (-not $allHealthy) { exit 1 }