Skip to content

fix: trusted dispatchers no longer rate-limited; agent survives reloa… - #1

Open
AlexOConnor212 wants to merge 1 commit into
mainfrom
fix/agent-rate-limit-wedge
Open

AlexOConnor212 wants to merge 1 commit into
mainfrom
fix/agent-rate-limit-wedge

Conversation

@AlexOConnor212

Copy link
Copy Markdown
Collaborator

See changelog file for changes

…d; fan-out failures self-describing

The recurring `exit -1 / "no response from child"` outage was the agent's
per-IP volume limiter (10 connections / 60 s, 300 s block) counting the
paired dispatcher's own connections and then closing its socket silently
after the handshake. Every run, ping, result poll and discovery is a fresh
mTLS connection, so ~10 operations in a minute from the one legitimate
caller blocked it for five minutes.

Agent (bin/ctrl-exec-agent, Exec::Agent::Server, Exec::RateLimit, Exec::Http):
- read the peer cert serial before the rate check; serials in the
  trusted-dispatcher map are exempt from the volume limit and never counted.
  Probe limit, max_children, allowed_ips and the per-request trusted-serial
  gate are unchanged.
- a blocked peer gets HTTP/1.0 429 {status,error,retry_after} before the
  close instead of a silent drop (new Exec::RateLimit::blocked_for).
- the accept-failure branch no longer exits the serve loop on every failed
  accept: it called peerhost on the listening socket (always ENOTCONN)
  before testing $!, so a bad handshake or the EINTR from a SIGHUP reload
  looked fatal. errno is captured first and classified by
  accept_failure_action (retry / handshake / fatal only for EBADF, EINVAL,
  ENOTSOCK); 20 consecutive failures add a 50 ms pause.
- peer_serial frees the X509 from get_peer_certificate (one leaked per
  connection in the long-lived parent); connection timestamps are not
  recorded when the limiter is disabled.

Dispatcher (Exec::Engine):
- _fan_out workers ignore SIGPIPE, reset the inherited INT/TERM exit-0
  handlers and run under eval; the parent keeps each wait status and reports
  outstanding workers if waitpid fails. The 'no response from child'
  fallbacks now append the reason (killed by signal N / exited N with no
  output / died: msg / waitpid: errno).
- 429 maps to an explanatory transport error; agent bodies decode through
  _json_hash so a non-object JSON body cannot die inside a worker.

Docs: CHANGELOG 0.12.4, REFERENCE.md exemption + 429, TESTING.md key name is
rate_limit_disable, agent.conf.example. Tests: new t/agent-accept.t plus
cases in fan-out, rate-limit, http, engine, transport-error (967 pass).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant