mirror of
https://github.com/Dvorinka/Containr.git
synced 2026-10-28 15:51:26 +00:00
Services gain sleep_enabled + sleep_idle_minutes. A 30s sweeper tracks container NetworkIO deltas; a flat counter for the configured window scales the service to zero (status=sleeping, workload containers removed). While slept, a busybox wake container takes over the service's Traefik host rule at priority 100: it serves a self-reloading "waking" page and calls the unauthenticated idempotent GET/POST /api/v1/internal/wake/:id, which reconciles the service back to running. Wake placeholders carry a dedicated label (containr.wake-for) so runtime state never counts them; the sweeper prunes them once the workload is up. The wake URL resolves the API via its container name when containerized, else the edge network's IPAM gateway — bare-metal installs need HOST=0.0.0.0 for the callback. Surfaces: PUT fields on services, POST /services/:id/sleep|wake, CLI --sleep/--sleep-idle + services sleep|wake, 2 MCP tools (89 total), OpenAPI paths/schema, and a Settings > Sleep card with toggle, idle minutes, and manual sleep/wake plus a Sleeping badge. Verified live: idle sweep scaled whoami-web to zero; the wake container served the page on the edge network and its callback woke the service (container recreated, status running, placeholder pruned). Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
42 lines
887 B
Go
42 lines
887 B
Go
package api
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
func TestMarkIdleTracksCounter(t *testing.T) {
|
|
id := uuid.New()
|
|
timeout := 50 * time.Millisecond
|
|
|
|
// First sighting sets the baseline only.
|
|
if markIdle(id, 100, timeout) {
|
|
t.Fatal("slept on first sighting")
|
|
}
|
|
// Counter growth resets the idle clock.
|
|
if markIdle(id, 200, timeout) {
|
|
t.Fatal("slept while counter grew")
|
|
}
|
|
// Flat counter within the window doesn't sleep.
|
|
if markIdle(id, 200, timeout) {
|
|
t.Fatal("slept before timeout")
|
|
}
|
|
time.Sleep(60 * time.Millisecond)
|
|
if !markIdle(id, 200, timeout) {
|
|
t.Fatal("did not sleep after timeout")
|
|
}
|
|
}
|
|
|
|
func TestMarkIdleZeroCounterSleeps(t *testing.T) {
|
|
id := uuid.New()
|
|
timeout := 20 * time.Millisecond
|
|
|
|
markIdle(id, 0, timeout)
|
|
time.Sleep(30 * time.Millisecond)
|
|
if !markIdle(id, 0, timeout) {
|
|
t.Fatal("zero-traffic service never slept")
|
|
}
|
|
}
|