Skip to content

say whether the proxy is actually there, instead of falling back in silence - #2800

Merged
Flotapponnier merged 3 commits into
mainfrom
fix/birdeye-proxy-visibility
Oct 4, 2026
Merged

Flotapponnier merged 3 commits into
mainfrom
fix/birdeye-proxy-visibility

Conversation

@Flotapponnier

Copy link
Copy Markdown
Collaborator

Birdeye's edge refuses this project's Railway egress, so the dial only works through the proxy. getProxyDialer falls back to a direct dial when HTTP_PROXY is missing, silently, and that fallback makes two different failures look identical: no proxy configured, and a proxy that is itself refused.

It cost an afternoon. The same dialer shape, with the same proxy URL read out of Railway, connects from a laptop:

configuration result
Proxy only 101
Proxy + custom NetDialContext 101
getProxyDialer shape 101

while the deployed service answers 403 on every attempt. So the dialer is not the problem and the proxy is not refused. The remaining candidate is that the variable is not in the container's environment at all — which is precisely what nothing in the logs could tell me.

Startup now prints which of the two it is. No value is logged, only its length.

Checks

  • go build ./... and go test ./cmd/script/ clean

🤖 Generated with Claude Code

Flotapponnier and others added 3 commits October 4, 2026 14:59
Deployed to one region and watched it. Every dial is answered 403 from
Railway, and the monitor did what I wrote it to do: back off, retry, back
off, retry, for as long as it runs. Three regions and two chains each,
against an endpoint refusing all six, indefinitely. That is hammering a
third party for no measurement, and it ran in production before I caught
it.

The 403 is not transient and not a header problem, which is what my own
error message claimed. The same dial, same headers, same binary:

  laptop, residential     101
  OVH VPS, datacenter     101
  Railway EU West         403

So the edge is scoring the egress IP. Retrying cannot change that, and a
monitor that cannot tell "come back later" from "not from here" will keep
asking forever.

A 403 now returns a sentinel, and three consecutive ones disable that
chain with a message saying what is actually wrong. Ordinary disconnects
still reconnect as before; a test pins that distinction, because a breaker
that also swallowed a dropped socket would silently stop measuring a
provider that was merely flaky.

This does not make Birdeye work from Railway. It makes its failure quiet
and honest instead of loud and useless. Whether to route Railway through
a proxy, run this chain from the VPS, or drop Birdeye is a separate
decision with its own costs.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
HTTP_PROXY and HTTPS_PROXY are set on all three Railway services, and
getProxyDialer() reads them. geckoterminal_monitor.go and both mobula
paths already dial that way; I hardcoded a bare websocket.Dialer, so
Birdeye went direct from an egress IP Cloudflare refuses.

That is the whole reason it returned 403 from Railway while the same
binary got 101 from a laptop and from the OVH VPS. I had reported that
no proxy was configured, which was wrong: my grep was anchored to the
start of the line and missed both variables.

The breaker in the previous commit stays. If the proxy is also refused,
three 403s still disable the chain rather than retrying forever.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ilence

Birdeye's edge refuses this project's Railway egress, so the dial only
works through the proxy. getProxyDialer falls back to a direct dial when
HTTP_PROXY is missing, silently, and that fallback makes two different
failures look identical: no proxy configured, and a proxy that is itself
refused.

It cost an afternoon. The same dialer shape, with the same proxy URL read
out of Railway, connects from a laptop:

  Proxy only                      101
  Proxy + custom NetDialContext   101
  getProxyDialer shape            101

while the deployed service answers 403 on every attempt. So the dialer is
not the problem and the proxy is not refused; the remaining candidate is
that the variable is not in the container's environment at all, which is
precisely what nothing in the logs could tell me.

Startup now prints which of the two it is. No value is logged, only its
length.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@Flotapponnier
Flotapponnier merged commit 2f0790e into main Oct 4, 2026
2 checks passed
@Flotapponnier
Flotapponnier deleted the fix/birdeye-proxy-visibility branch October 4, 2026 13:26
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