## Critical Gotchas ### ⚠️ WebSocket: fetch() vs containerFetch() **Problem:** WebSocket connections fail silently **Cause:** `containerFetch()` doesn't support WebSocket upgrades **Fix:** Always use `fetch()` for WebSocket ```typescript // ❌ WRONG return container.containerFetch(request); // ✅ CORRECT return container.fetch(request); ``` ### ⚠️ startAndWaitForPorts() vs start() **Problem:** "connection refused" after `start()` **Cause:** `start()` returns when process starts, NOT when ports ready **Fix:** Use `startAndWaitForPorts()` before requests ```typescript // ❌ WRONG await container.start(); return container.fetch(request); // ✅ CORRECT await container.startAndWaitForPorts(); return container.fetch(request); ``` ### ⚠️ Activity Timeout on Long Operations **Problem:** Container stops during long work **Cause:** `sleepAfter` based on request activity, not internal work **Fix:** Renew timeout by touching storage ```typescript const interval = setInterval(() => { this.ctx.storage.put("keepalive", Date.now()); }, 60000); try { await this.doLongWork(data); } finally { clearInterval(interval); } ``` ### ⚠️ blockConcurrencyWhile for Startup **Problem:** Race conditions during initialization **Fix:** Use `blockConcurrencyWhile` for atomic initialization ```typescript await this.ctx.blockConcurrencyWhile(async () => { if (!this.initialized) { await this.startAndWaitForPorts(); this.initialized = true; } }); ``` ### ⚠️ Lifecycle Hooks Block Requests **Problem:** Container unresponsive during `onStart()` **Cause:** Hooks run in `blockConcurrencyWhile` - no concurrent requests **Fix:** Keep hooks fast, avoid long operations ### ⚠️ Don't Override alarm() When Using schedule() **Problem:** Scheduled tasks don't execute **Cause:** `schedule()` uses `alarm()` internally **Fix:** Implement `alarm()` to handle scheduled tasks ## Common Errors ### "Container start timeout" **Cause:** Container took >8s (`start()`) or >20s (`startAndWaitForPorts()`) **Solutions:** - Optimize image (smaller base, fewer layers) - Check `entrypoint` correct - Verify app listens on correct ports - Increase timeout if needed ### "Port not available" **Cause:** Calling `fetch()` before port ready **Solution:** Use `startAndWaitForPorts()` ### "Container memory exceeded" **Cause:** Using more memory than instance type allows **Solutions:** - Use larger instance type (standard-2, standard-3, standard-4) - Optimize app memory usage - Use custom instance type ```jsonc "instance_type_custom": { "vcpu": 2, "memory_mib": 8192 } ``` ### "Max instances reached" **Cause:** All `max_instances` slots in use **Solutions:** - Increase `max_instances` - Implement proper `sleepAfter` - Use `getRandom()` for distribution - Check for instance leaks ### "No container instance available" **Cause:** Account capacity limits reached **Solutions:** - Check account limits - Review instance types across containers - Contact Cloudflare support ## Limits | Resource | Limit | Notes | |----------|-------|-------| | Cold start | 2-3s | Image pre-fetched globally | | Graceful shutdown | 15 min | SIGTERM → SIGKILL | | `start()` timeout | 8s | Process start | | `startAndWaitForPorts()` timeout | 20s | Port ready | | Max vCPU per container | 4 | standard-4 or custom | | Max memory per container | 12 GiB | standard-4 or custom | | Max disk per container | 20 GB | Ephemeral, resets | | Account total memory | 400 GiB | All containers | | Account total vCPU | 100 | All containers | | Account total disk | 2 TB | All containers | | Image storage | 50 GB | Per account | | Disk persistence | None | Use DO storage | ## Best Practices 1. **Use `startAndWaitForPorts()` by default** - Prevents port errors 2. **Set appropriate `sleepAfter`** - Balance resources vs cold starts 3. **Use `fetch()` for WebSocket** - Not `containerFetch()` 4. **Design for restarts** - Ephemeral disk, implement graceful shutdown 5. **Monitor resources** - Stay within account limits 6. **Keep hooks fast** - Run in `blockConcurrencyWhile` 7. **Renew activity for long ops** - Touch storage to prevent timeout ## Beta Caveats ⚠️ Containers in **beta**: - **API may change** without notice - **No SLA** guarantees - **Limited regions** initially - **No autoscaling** - manual via `getRandom()` - **Rolling deploys** only (not instant like Workers) Plan for API changes, test thoroughly before production.