Skip to content

feat(code.gs): optional spreadsheet-backed response cache with TTL#443

Merged
therealaleph merged 2 commits intotherealaleph:mainfrom
euvel:feat/spreadsheet-cache
Apr 28, 2026
Merged

feat(code.gs): optional spreadsheet-backed response cache with TTL#443
therealaleph merged 2 commits intotherealaleph:mainfrom
euvel:feat/spreadsheet-cache

Conversation

@euvel
Copy link
Copy Markdown
Contributor

@euvel euvel commented Apr 28, 2026

Summary

Adds an optional spreadsheet-backed response caching layer to Code.gs that reduces UrlFetchApp quota consumption by serving repeat public GET requests from a Google Sheet.

All five review suggestions from the discussion thread are addressed:

  • TTL-aware caching_parseMaxAge() reads Cache-Control: max-age, respects no-cache/no-store/private, stores an Expires_At column, and skips expired entries on lookup. Falls back to 24 hours when no Cache-Control header is present.
  • 35 KB body-size gateCACHE_MAX_BODY_BYTES = 35000 prevents hitting the 50,000-character Sheets cell limit. Oversized responses are returned to the user but skipped for storage.
  • Header rewriting on cache hitDate, Age, and Cache-Control are recalculated to reflect time-since-cache. Original Cache-Control is preserved in X-Original-Cache-Control. Diagnostic headers X-Cache: HIT from relay-spreadsheet and X-Cached-At are added.
  • Circular buffer (O(1) writes) — A hidden RelayMeta sheet tracks a write cursor that wraps at CACHE_MAX_ROWS. Replaces appendRow / deleteRows, eliminating reindexing overhead.
  • Vary-aware compound cache keysAccept-Encoding and Accept-Language are hashed alongside the URL using case-insensitive matching and whitespace normalization. Covers ~95% of real-world Vary usage without inspecting the response.

Design Discussion

See this issue thread for full discussion and reviewer feedback.

Configuration

Opt-in via a single constant at the top of Code.gs:

const CACHE_SPREADSHEET_ID = "YOUR_SPREADSHEET_ID_HERE";

Leave as-is to disable caching entirely — zero overhead, no behavioral change for existing deployments.

How to Test

  1. Create a new Google Sheet and copy its ID from the URL
  2. Set CACHE_SPREADSHEET_ID to that ID in Code.gs
  3. Deploy as a new Web App (Deploy -> New deployment)
  4. Use the proxy to browse a few sites
  5. Open the spreadsheet — the RelayCache sheet will populate with cached responses
  6. Run getCacheStats() from the Apps Script editor to view stats

Breaking Changes

None. The cache is off by default.

@github-actions github-actions Bot added the type: feature feat: PR — auto-applied by release-drafter label Apr 28, 2026
@therealaleph therealaleph merged commit 84ea21c into therealaleph:main Apr 28, 2026
1 check passed
therealaleph added a commit that referenced this pull request Apr 28, 2026
…er errors

Three substantive PRs from contributors landed for this release:

- #443 by @euvel: optional spreadsheet-backed response cache in Code.gs.
  Implements all 5 review suggestions from the design discussion (#400):
  TTL-aware caching, 35 KB body-size gate, header rewriting on hit,
  circular buffer for O(1) writes, Vary-aware compound keys.

- #439 by @dazzling-no-more: bypass Apps Script tunnel for known DoH
  endpoints on TCP/443. Cloudflare/Google/Quad9/AdGuard/NextDNS/OpenDNS/
  CleanBrowsing/dns.sb/dns0.eu/AliDNS/doh.pub/Mullvad. Saves the ~2s
  UrlFetchApp roundtrip per name without losing privacy (DoH is
  already encrypted). Default on; users can opt out via tunnel_doh: true
  or extend the list via bypass_doh_hosts.

- #438 by @dazzling-no-more: H1 container keepalive + 431 oversized-
  headers + clearer port-collision message. Cherry-picks from upstream
  Python (Apr 23-26 window). Keepalive prevents Apps Script V8 cold
  starts (visible as YouTube stalls after pause); 431 replaces silent
  socket drops on >64 KB headers (which caused browser retry loops).
@therealaleph
Copy link
Copy Markdown
Owner

Merged + included in v1.8.3 (just tagged). Builds clean, all 160 tests pass on main. Thanks for shipping this — exactly the kind of contribution that scales the project beyond what one maintainer can ship alone.

v1.8.3 release page: https://github.com/therealaleph/MasterHttpRelayVPN-RUST/releases/tag/v1.8.3

Telegram channel announcement: https://t.me/mhrv_rs (will fire once release CI completes)

Will tag you on the v1.9.0 xmux design issue when drafted (~1-2 weeks).


[reply via Anthropic Claude | reviewed by @therealaleph]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type: feature feat: PR — auto-applied by release-drafter

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants