Skip to content

feat(code.gs): gzip cache bodies + status-aware TTL (skip 5xx, cap persistent 4xx)#953

Merged
therealaleph merged 1 commit intotherealaleph:mainfrom
dazzling-no-more:feature/apps-script-cache-gzip-and-negative
May 9, 2026
Merged

feat(code.gs): gzip cache bodies + status-aware TTL (skip 5xx, cap persistent 4xx)#953
therealaleph merged 1 commit intotherealaleph:mainfrom
dazzling-no-more:feature/apps-script-cache-gzip-and-negative

Conversation

@dazzling-no-more
Copy link
Copy Markdown
Contributor

Summary

Three improvements to the optional spreadsheet response cache in Code.gs. They compound: more URLs become cacheable, the cache stops being poisoned by transient outages, and 4xx storms cost zero quota.

1. Gzip body before base64 storage. _fetchAndCache now stores base64(gzip(rawBytes)) (marked with a new Z column) when the response is not already content-encoded and is over 256 bytes. Most cacheable text bodies (HTML / JSON / JS / CSS) compress 3–5×, so a ~100–150 KB pre-compressed response now fits under the unchanged 35 KB cell ceiling where it previously bailed. Skip-when-already-encoded prevents double-compressing gzip/br/zstd payloads; skip-when-tiny avoids gzip's ~20-byte header bloating sub-256-byte responses. _getFromCache decompresses on hit and re-base64s for the wire — relay protocol b field stays base64(rawBytes), no client change.

2. 5xx never enters the cache. Previously, a single 503 from a flapping upstream would pin that response for 24 h (the default TTL fallback) and break the URL for every subsequent client until expiry. Now status >= 500 early-returns the live response without writing to the sheet.

3. Negative caching for persistent 4xx. 404 / 410 / 451 with no upstream Cache-Control get a 5-minute TTL instead of the 24-hour default. Long enough to absorb buggy clients hammering favicons / telemetry pixels / dev-tools probes at zero quota cost; short enough that transient 404s (e.g. eventual-consistency CDN misses) self-heal quickly. If upstream explicitly stated a max-age, we honor it instead — origin knows best when it spoke up.

Schema migration

Cache sheet grew from 7 columns to 8 (added Z flag). New deployments get the 8-column header; existing deployments keep their old 7-column header (cosmetic only — getCacheStats doesn't read it). Legacy 7-column rows read back with Z = undefined, which is falsy and falls through the not-gzipped branch — fully backward-compatible, no user action required.

Behavior change to flag

For users relying on the previous "everything cached for 24 h" default:

  • 5xx is no longer cached (this was effectively a bug — fix is intentional).
  • 404 / 410 / 451 are now cached for 5 min instead of 24 h when upstream is silent on Cache-Control. Set Cache-Control: max-age=... on the origin if you actually want long negative caching.

No behavior change for 2xx, 3xx, other 4xx, or any response where upstream specified a Cache-Control directive — those continue to honor stated max-age (or 24 h default).

Scope

Code.gs only. CodeFull.gs doesn't have the spreadsheet response cache (it has a separate CacheService-backed edge DNS cache, which doesn't benefit from these changes). Code.cfw.gs runs the actual fetch on a Cloudflare Worker, so caching would have to live there. Both are out of scope.

Test plan

  • node --check parses Code.gs cleanly
  • Diff review: no remaining getRange(..., 7) or setValues widths of 7 outside meta-sheet ops
  • Backward-compat verified by inspection: legacy 7-column rows read with row[7] === undefined → falsy → not-gzipped branch

@github-actions github-actions Bot added the type: feature feat: PR — auto-applied by release-drafter label May 9, 2026
@therealaleph therealaleph merged commit 072a917 into therealaleph:main May 9, 2026
1 check passed
@dazzling-no-more dazzling-no-more deleted the feature/apps-script-cache-gzip-and-negative branch May 9, 2026 19:07
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