Repository navigation
Count proxy traffic per run and stop at --proxy-budget-mb (default 10 MB) - #47
Merged
Merged
Conversation
… MB) A browser this repo launches behind --proxy / --proxy-file now counts the bytes it sends through the proxy (Playwright: request.sizes(); pyppeteer and Selenium: CDP Network.loadingFinished.encodedDataLength plus request sizes; the pre-check HEAD too). Once the total passes --proxy-budget-mb no further listing, worker or product page is opened, the browser aborts what it still tries, the products read so far are kept, and the run exits 6 (5 with none) with stop_reason proxy_budget_exceeded. The sidecar records proxy_bytes, proxy_budget_bytes and proxy_budget_exceeded, and the run ends with one "Proxy traffic: X.X MB of Y MB budget" line. Nothing is metered over --cdp-endpoint or without a proxy. The production-like canary passes --proxy-budget-mb 10, writes its traffic to the job summary and fails when the budget was hit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CKsd7q25N19WzUZjrAdzx8
…y ISO time A budget tripped on a thread without an event loop could not send the pyppeteer page's Network.setBlockedURLs; the block is now scheduled on the page's own loop. The canary's traffic summary compared finished_at values directly, which raises when one sidecar carries an ISO-8601 string and the other none; it now parses epoch seconds or ISO-8601. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CKsd7q25N19WzUZjrAdzx8
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
A run through a residential proxy is billed per byte, and nothing measured or limited what a run sent through it.
Resulting behaviour
Only for a browser this repo launches behind
--proxy/--proxy-file/FARFETCH_PROXY. Nothing changes with--cdp-endpointor with no proxy.proxy_meter.py) — an estimate of the tunnelled payload (TLS/CONNECToverhead, WebSocket frames and the browser's own background requests not included):request.sizes()(request headers + body, response headers + body) onrequestfinished/requestfailed, in every worker under--concurrencytoo.Network.loadingFinished.encodedDataLengthforhttp(s)responses that came over the network plus the request line/headers/body fromNetwork.requestWillBeSent. Chrome's own error page,chrome://pages and cache hits are not counted.HEADcounts too.--proxy-budget-mbon all three engines (default 10, 0 = unlimited; a negative or non-number value is exit 2). Flag only:ENV_KEYSmaps only credentials and URLs. Once the total passes it, no further listing page, worker page or product page is opened. Playwright aborts every further request (a route registered after the media route, elsefallback()), and pyppeteer and Selenium setNetwork.setBlockedURLs ["*"]. The products read so far are kept. In--mode detail, a budget spent on the listing opens no product page, and listing rows are never written as size rows.finish_runputsstop_reason: proxy_budget_exceededabove every other outcome. That gives exit 6 with rows and 5 without, never 3 or 4.proxy_bytes,proxy_budget_bytes,proxy_budget_exceeded(null/null/falsewithout a local proxy). A proxied run that writes no rows now records its outcome and bytes in<out>.latest_attempt.meta.json, and the data and.meta.jsonstay untouched. The run prints one line at the end:Proxy traffic: X.X MB of Y MB budget.--proxy-budget-mb 10. An always-run step,.github/proxy_traffic_summary.py, appends**production-like**: proxy traffic X.X MB of 10 MBto$GITHUB_STEP_SUMMARY. If the run stopped at the budget, the step prints::error::stopped: proxy budget 10 MB exceededand fails. A missing or unreadable sidecar is reported and does not fail the step. The latest_attempt sidecar is uploaded with the artifacts.Evidence (offline; no proxy, no paid call, no canary dispatched)
tests/test_proxy_meter.pyruns a stub forward proxy that serves a page of known size (~152 KB of html, js, css and a fetched JSON) and counts the bytes crossing its sockets. Against its count:ERR_BLOCKED_BY_CLIENT.CI engine jobs now install Playwright's Chromium and run this file with
PROXY_METER_REQUIRE=<engine>, so a missing browser fails rather than skips.The real CLIs through the stub proxy (CONNECT answered 403, so farfetch.com is never reached):
Proxy traffic: 0.0 MB of 10 MB budgetand an attempt sidecar recordingproxy_bytes;chrome://scripts that are reported as finished loads. The CDP count is now limited tohttp(s)responses.Results per environment:
pytest -q: 502 passed;proxy_meter.pyadded to the gated files.New checks, per engine through fake browsers:
(1200, 1000, True), one summary line;--concurrency 2: workers stop taking pages;--mode detail: no product page is opened;An existing check ("the canary never puts the proxy credential in argv") matched the substring
--proxy. It now looks for--proxy/--proxy=/--proxy-file, because--proxy-budget-mb 10carries no credential.Planted-fault controls. Each went red on the named checks, then green once restored:
Follow-up commit:
Network.setBlockedURLs: it is scheduled on the page's loop withcall_soon_threadsafe. A new test triggers the budget from a worker thread; it went red with the old code.finished_at(epoch or ISO-8601; this repo writes ISO). The old direct comparison raisedTypeErrorwhen one sidecar carried an ISO string and the other none. A new check covers that case and went red on the old code.Not changed
No version bump or release, and no canary was dispatched. The pyppeteer
page.authenticateproxy auth is unchanged (a known gap on current Chromium). Chrome's background traffic is not suppressed.🤖 Generated with Claude Code
https://claude.ai/code/session_01CKsd7q25N19WzUZjrAdzx8