From 2c3c92c3b7c85042b448ba1a1b73e8ca0c3f0092 Mon Sep 17 00:00:00 2001 From: S'Bussiso Dube <80188685+Sbussiso@users.noreply.github.com> Date: Wed, 9 Sep 2026 13:38:26 -0700 Subject: [PATCH] =?UTF-8?q?Keep=20the=20agent=20warm=20=E2=80=94=20Fly's?= =?UTF-8?q?=20proxy=20won't=20wait=20for=20it=20to=20boot?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The agent scaled to zero, and every wakeup against a stopped machine failed with RemoteDisconnected. Fly's proxy waits ~8s for an auto-started machine to bind its port; this process takes longer: before LiteLLM ~7s (fit, barely) after LiteLLM ~16s (broke) after deferring litellm's import ~10s (still broke) So deferring the import was necessary but not sufficient, and the 7s figure says this was always marginal — LiteLLM only exposed it. The remaining time is Python plus the MCP SDK plus Sentry, and trimming that further means tuning against a proxy timeout we do not control and can only observe in production. Keeping one 512MB machine warm costs about $2/month — noise against the LLM spend of a single run — and removes cold starts from the wakeup path instead of racing them. Scale-to-zero was the right shape when the agent was its own app answering a public webhook; it is not worth this. Co-Authored-By: Claude Opus 5 --- fly.toml | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/fly.toml b/fly.toml index 595269e..e9f410d 100644 --- a/fly.toml +++ b/fly.toml @@ -95,18 +95,31 @@ primary_region = "sjc" # publicly: it is reachable at http://sentinel-command.flycast:8080 over # 6PN, which is where SENTINEL_AGENT_WEBHOOK_URL points. # -# This service is what makes scale-to-zero work at all. Fly auto-starts a -# stopped machine on a connection to one of its SERVICES; a bare 6PN -# connection to a stopped machine just fails. So the wakeup webhook both -# starts the machine and delivers the work. -# # Requires a private IPv6 on the app: `fly ips allocate-v6 --private`. +# +# NOT scaled to zero, despite that being this worker's obvious shape, and +# despite it being how the agent ran as its own app. Fly's proxy waits +# only ~8s for a machine it auto-started to bind its port, and this +# process cannot reliably beat that: Python plus the MCP SDK plus Sentry +# took ~7s before LiteLLM and ~10s after — so an auto-started machine got +# declared unreachable and Command Center's wakeup came back +# RemoteDisconnected. Measured, twice, on 2026-09-09. +# +# The 7s figure means this was always marginal and happened to fit; the +# LiteLLM move only exposed it. Deferring litellm's import cut boot from +# 16s to 10s, which was necessary but not sufficient, and trimming +# further imports would be tuning against a proxy limit we do not +# control and cannot test except in production. +# +# So the agent stays warm. One shared-cpu-1x/512MB machine is ~$2/month, +# which is noise against the LLM spend of a single run, and it removes +# cold starts from the wakeup path entirely rather than racing them. [[services]] internal_port = 8080 protocol = "tcp" - auto_stop_machines = "stop" + auto_stop_machines = "off" auto_start_machines = true - min_machines_running = 0 + min_machines_running = 1 processes = ["agent"] [[services.ports]]