docs(canvas): correct CF DO limits in resize doc and plan

Earlier docs assumed a 1 GB per-DO storage cap. Actual May 2026 free-tier
limits per the CF DO docs:
- 10 GB per Durable Object
- 5 GB per account (the real Free-tier ceiling)
- 2 MB per BLOB row
- 1,000 req/sec soft cap per DO

Practical effect: canvas can grow to ~70,000 × 70,000 on Free (was previously
documented as ~32K × 32K). Existing 64 KB CHUNK_BYTES is well-suited:
clustered writes (single pixels + image patches) minimize read-modify-write
amplification; bigger chunks would only help uniform-random writes which
isn't rplace's workload.

No code change. Just doc accuracy.
This commit is contained in:
tiennm99 committed 2026-05-10 00:07:39 +07:00
1 parent c3f7c02f6d
commit cdf2295ef6
3 files changed
+22 -6

No files matched your search

+10 -5
View File
@@ -38,14 +38,19 @@ needed.
- **Aspect ratio change** (non-square) is fine. The 1-D byte-layout
(`y * CANVAS_WIDTH + x`) still holds. Just make sure clients pull
the new constants too — frontend reads them from the same module.
- **Storage cap.** SQLite-backed DO storage is 1 GB on the Free plan.
A 1-byte-per-pixel canvas fits up to roughly **32,768 × 32,768**
before hitting that ceiling.
- **Storage caps (Cloudflare Free plan, 2026).**
- Per Durable Object: **10 GB** (would allow ~100,000 × 100,000)
- Per Account: **5 GB** (the real ceiling on Free)
- At 1 byte per pixel, the practical free-tier ceiling is roughly
**70,000 × 70,000 pixels** (≈4.9 GB).
- SQLite BLOB row cap is **2 MB**; our 64 KB `CHUNK_BYTES` has 32× headroom
so resizing never touches that limit.
## Free-tier monitoring
After resize, watch:
- Cloudflare Workers requests/day (free cap: 100,000)
- Durable Object storage size (free cap: 1 GB per DO)
- Durable Object storage (free caps: 10 GB per DO, 5 GB per account)
- Per-DO request rate (soft cap: 1,000 req/sec)
Both visible on the Cloudflare dashboard for the rplace project.
All visible on the Cloudflare dashboard for the rplace project.
@@ -39,6 +39,15 @@ export const CHUNK_BYTES = 65536; // 64
export const CHUNK_COUNT = Math.ceil(TOTAL_PIXELS / CHUNK_BYTES); // 256
```
**Why 64 KB chunks (informed by actual CF DO limits, May 2026):**
- BLOB row cap is **2 MB** → `CHUNK_BYTES` could be up to ~2 MB; we use 64 KB (32× under).
- Storage caps are **10 GB / DO** and **5 GB / account** (Free) → 16 MB canvas
is ~300× under either cap; resize to ~70K×70K is feasible on Free.
- Soft request cap is **1,000 req/sec / DO** → hobby workload is 1‰ of this.
- Smaller chunks minimize read-modify-write amplification on **clustered** writes
(single placements + image patches), which is rplace's actual workload pattern.
Bigger chunks would only help uniform-random writes — not a real workload here.
Schema (created in DO constructor via `sql.exec` if not exists):
```sql
@@ -73,7 +73,9 @@ Phase order is strict: 1 → 2 → 3 → 4 → 5. Each phase blocks the next.
| Test rewrite scope creep | Low | Time-box testcontainers→DO test rewrite to 4h; cut e2e if needed |
| Migration corrupts canvas | High | Keep Upstash data 7 days post-migration as rollback |
| DO single-region latency regression | Low | Same as today's Upstash (single region) — no change |
| Storage billing exposure if canvas grows | Med | Monitor; current 16 MB << 1 GB threshold |
| Storage exposure if canvas grows | Low | Per-DO 10 GB / per-account 5 GB on Free; current 16 MB has 300× headroom |
| BLOB row size cap (2 MB) | None | `CHUNK_BYTES = 64 KB` has 32× headroom from this limit |
| Per-DO 1,000 req/sec soft cap | None | Hobby load is ~1 req/sec; edge cache absorbs `/api/canvas` |
## Rollback Plan