carlos / platform Public

Exec wake: a hibernated app's leftover socket makes every later wake fail (503 forever) Issue open

Migrated from github.com/carlosframework/platform issue #129, opened 2026-08-09. GitHub issues are closed for this repo; see AGENTS.md, "Work is tracked on amadan, not GitHub".

Still outstanding: A hibernated app's leftover socket wedges every later wake into a permanent 503; the fix (unlink when nothing is listening) is unbuilt.

---

Found in production 2026-08-09 on hello.bdf.oncarlos.com (the carloku.com homepage demo app).

Shape: an exec-backed instance hibernates — process stops, route stays — and the unix socket file it bound survives at /run/carlos/<host>.sock. The activator spawns the child again on the next request, the child's net.Listen("unix", …) fails with bind: address already in use, and the wake never succeeds. The edge serves instance failed to wake (503) on every request from then on — it does not self-heal, because each retry hits the same leftover.

Box journal:

carlos[72437]: listen unix /run/carlos/hello.bdf.oncarlos.com.sock: bind: address already in use
carlos[63872]: activator: wake hello.bdf.oncarlos.com: start …: instance not healthy within 30s: … connect: connection refused

Today the app must unlink its own socket. The CARLOS framework does (rastrillo/serve.go: os.Remove(socket) before listen), so framework apps are fine — but any app written straight to the contract (<bin> --socket <path> --db <path>) works on first deploy and then breaks the first time it goes idle. That is a nasty trap: it passes every test, ships green, and dies 15 minutes later.

Suggested fix: in ExecBackend.Start, unlink the route's socket before spawning only when nothing is listening on it (dial fails). The "nothing is listening" condition is exactly the stale definition, and it preserves the #17 external-socket advisory case, where a live socket is legitimately served by a process the platform does not manage — that one must still be left alone.

Also worth doing either way: say it in the app-author docs. Right now the contract is discoverable only by reading backend_exec.go or losing an afternoon.

Workaround applied to the demo app: carlosframework/hello@6c88010 (unlink + a regression test that reproduces the exact bind error).