fix: overhaul container lifecycle — recovery, health, uninstall, UI state
Container recovery: - Health monitor: MAX_RESTART_ATTEMPTS 3→10, interval 60s→120s - Dependency-aware restarts: won't restart services before their deps - Reset dependent counters when a dependency recovers - Handle "created" state containers (were invisible to health monitor) - Added IndeedHub, mempool-api, mysql to tier system - Crash recovery: podman start timeout 30s→120s with retry - Podman client: socket timeout 5s→30s, added restart policy UI state representation: - Exit code 0 shows "stopped" (gray), not "crashed" (red) - Exit code 137 shows "killed (OOM)" - Non-zero exit shows "crashed" (red) - Added exit_code field to PackageDataEntry Install/uninstall fixes: - Install returns error when container doesn't start (was silent success) - Post-install hooks awaited instead of fire-and-forget tokio::spawn - Uninstall: graceful rm before force, volume prune, network cleanup - Uninstall returns error on partial failure (was 200 OK) Config consistency: - DB passwords read from /var/lib/archipelago/secrets/ (was hardcoded) - Bitcoin: added ZMQ ports 28332/28333 for LND block notifications - IndeedHub port 7777→8190 (was conflicting with strfry) - Marketplace versions: LND 0.17.4→0.18.4, Mempool 2.5.0→3.0.0 Performance: - Metrics collector interval 60s→300s (was duplicating health monitor) - Podman client: proper error propagation instead of unwrap_or_default Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
cdff10a8bc
commit
64b57dca7d
@@ -15,10 +15,10 @@
|
||||
<div class="flex items-center gap-2">
|
||||
<span
|
||||
class="inline-flex items-center px-2.5 py-1 rounded-lg text-xs font-medium"
|
||||
:class="getStatusClass(pkg.state, pkg.health)"
|
||||
:class="getStatusClass(pkg.state, pkg.health, pkg['exit-code'])"
|
||||
>
|
||||
<span class="w-1.5 h-1.5 rounded-full mr-1.5" :class="getStatusDotClass(pkg.state, pkg.health)"></span>
|
||||
{{ getStatusLabel(pkg.state, pkg.health) }}
|
||||
<span class="w-1.5 h-1.5 rounded-full mr-1.5" :class="getStatusDotClass(pkg.state, pkg.health, pkg['exit-code'])"></span>
|
||||
{{ getStatusLabel(pkg.state, pkg.health, pkg['exit-code']) }}
|
||||
</span>
|
||||
<span class="text-white/50 text-xs">v{{ pkg.manifest.version }}</span>
|
||||
</div>
|
||||
@@ -107,10 +107,10 @@
|
||||
<div class="flex flex-wrap items-center gap-2">
|
||||
<span
|
||||
class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium"
|
||||
:class="getStatusClass(pkg.state, pkg.health)"
|
||||
:class="getStatusClass(pkg.state, pkg.health, pkg['exit-code'])"
|
||||
>
|
||||
<span class="w-1.5 h-1.5 rounded-full mr-1" :class="getStatusDotClass(pkg.state, pkg.health)"></span>
|
||||
{{ getStatusLabel(pkg.state, pkg.health) }}
|
||||
<span class="w-1.5 h-1.5 rounded-full mr-1" :class="getStatusDotClass(pkg.state, pkg.health, pkg['exit-code'])"></span>
|
||||
{{ getStatusLabel(pkg.state, pkg.health, pkg['exit-code']) }}
|
||||
</span>
|
||||
<span class="text-white/50 text-xs">v{{ pkg.manifest.version }}</span>
|
||||
</div>
|
||||
|
||||
@@ -107,7 +107,7 @@ export function isRealOnionAddress(addr: string | undefined): boolean {
|
||||
return !!(addr && addr.endsWith('.onion') && addr.length >= 60 && addr.length <= 70)
|
||||
}
|
||||
|
||||
export function getStatusClass(state: PackageState, health?: string | null): string {
|
||||
export function getStatusClass(state: PackageState, health?: string | null, exitCode?: number | null): string {
|
||||
if (state === PackageState.Running && health === 'starting') return 'bg-yellow-500/20 text-yellow-200 border border-yellow-500/30'
|
||||
if (state === PackageState.Running && health === 'unhealthy') return 'bg-orange-500/20 text-orange-200 border border-orange-500/30'
|
||||
switch (state) {
|
||||
@@ -116,7 +116,9 @@ export function getStatusClass(state: PackageState, health?: string | null): str
|
||||
case PackageState.Stopped:
|
||||
return 'bg-gray-500/20 text-gray-200 border border-gray-500/30'
|
||||
case PackageState.Exited:
|
||||
return 'bg-red-500/20 text-red-200 border border-red-500/30'
|
||||
return exitCode != null && exitCode !== 0
|
||||
? 'bg-red-500/20 text-red-200 border border-red-500/30'
|
||||
: 'bg-gray-500/20 text-gray-200 border border-gray-500/30'
|
||||
case PackageState.Starting:
|
||||
case PackageState.Stopping:
|
||||
case PackageState.Restarting:
|
||||
@@ -128,7 +130,7 @@ export function getStatusClass(state: PackageState, health?: string | null): str
|
||||
}
|
||||
}
|
||||
|
||||
export function getStatusDotClass(state: PackageState, health?: string | null): string {
|
||||
export function getStatusDotClass(state: PackageState, health?: string | null, exitCode?: number | null): string {
|
||||
if (state === PackageState.Running && health === 'starting') return 'bg-yellow-400 animate-pulse'
|
||||
if (state === PackageState.Running && health === 'unhealthy') return 'bg-orange-400 animate-pulse'
|
||||
switch (state) {
|
||||
@@ -137,7 +139,9 @@ export function getStatusDotClass(state: PackageState, health?: string | null):
|
||||
case PackageState.Stopped:
|
||||
return 'bg-gray-400'
|
||||
case PackageState.Exited:
|
||||
return 'bg-red-400 animate-pulse'
|
||||
return exitCode != null && exitCode !== 0
|
||||
? 'bg-red-400 animate-pulse'
|
||||
: 'bg-gray-400'
|
||||
case PackageState.Starting:
|
||||
case PackageState.Stopping:
|
||||
case PackageState.Restarting:
|
||||
@@ -149,10 +153,14 @@ export function getStatusDotClass(state: PackageState, health?: string | null):
|
||||
}
|
||||
}
|
||||
|
||||
export function getStatusLabel(state: PackageState, health?: string | null): string {
|
||||
export function getStatusLabel(state: PackageState, health?: string | null, exitCode?: number | null): string {
|
||||
if (state === PackageState.Running && health === 'starting') return 'starting up'
|
||||
if (state === PackageState.Running && health === 'unhealthy') return 'unhealthy'
|
||||
if (state === PackageState.Running && health === 'healthy') return 'healthy'
|
||||
if (state === PackageState.Exited) return 'crashed'
|
||||
if (state === PackageState.Exited) {
|
||||
if (exitCode === 137) return 'killed (OOM)'
|
||||
if (exitCode != null && exitCode !== 0) return 'crashed'
|
||||
return 'stopped'
|
||||
}
|
||||
return state
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user