|
| 1 | +# Advanced Demo: `interpretManual()` |
| 2 | + |
| 3 | +> ⚠️ **WARNING: This demo shows an advanced pattern that is NOT RECOMMENDED for most applications.** |
| 4 | +
|
| 5 | +## What is this? |
| 6 | + |
| 7 | +This demo demonstrates `interpretManual()`, an alternative to `interpret()` that provides slightly faster actor creation at the cost of **manual lifecycle management**. |
| 8 | + |
| 9 | +## Should I use `interpretManual()`? |
| 10 | + |
| 11 | +**Almost certainly not.** |
| 12 | + |
| 13 | +| Question | If Yes | If No | |
| 14 | +|----------|--------|-------| |
| 15 | +| Are you creating thousands of actors per second? | Maybe consider it | Use `interpret()` | |
| 16 | +| Have you profiled and confirmed actor creation is a bottleneck? | Maybe consider it | Use `interpret()` | |
| 17 | +| Are you comfortable managing cleanup manually? | Maybe consider it | Use `interpret()` | |
| 18 | +| Is the 1.6x speedup significant for your use case? | Maybe consider it | Use `interpret()` | |
| 19 | + |
| 20 | +## Performance Comparison |
| 21 | + |
| 22 | +| Metric | `interpret()` | `interpretManual()` | |
| 23 | +|--------|--------------|---------------------| |
| 24 | +| Actor creation speed | Baseline | ~1.6x faster | |
| 25 | +| Cleanup | Automatic (via Scope) | **Manual** (you call `stop()`) | |
| 26 | +| Memory leak risk | None | **High if you forget cleanup** | |
| 27 | +| Code complexity | Simple | Complex | |
| 28 | +| Recommended | ✅ Yes | ❌ No (usually) | |
| 29 | + |
| 30 | +## The Problem with `interpretManual()` |
| 31 | + |
| 32 | +```typescript |
| 33 | +// With interpret() - cleanup is automatic |
| 34 | +const actor = yield* interpret(machine); |
| 35 | +// When Scope closes → finalizer runs → actor.stop() called automatically |
| 36 | + |
| 37 | +// With interpretManual() - YOU must cleanup |
| 38 | +const actor = Effect.runSync(interpretManual(machine)); |
| 39 | +// If you forget to call actor.stop(), the actor LEAKS: |
| 40 | +// - Activities keep running forever |
| 41 | +// - Timers keep firing |
| 42 | +// - Memory is never freed |
| 43 | +``` |
| 44 | + |
| 45 | +## Required Cleanup Pattern |
| 46 | + |
| 47 | +If you DO use `interpretManual()`, you MUST handle cleanup: |
| 48 | + |
| 49 | +```tsx |
| 50 | +// In React: |
| 51 | +useEffect(() => { |
| 52 | + const actor = Effect.runSync(interpretManual(machine)); |
| 53 | + |
| 54 | + return () => { |
| 55 | + actor.stop(); // CRITICAL! Without this, you leak! |
| 56 | + }; |
| 57 | +}, []); |
| 58 | +``` |
| 59 | + |
| 60 | +## Why does `interpretManual()` exist? |
| 61 | + |
| 62 | +For rare cases where: |
| 63 | +1. You're creating many short-lived actors |
| 64 | +2. Actor creation overhead is a measured bottleneck |
| 65 | +3. You're managing lifecycle manually anyway |
| 66 | +4. The ~1.6x speedup matters for your use case |
| 67 | + |
| 68 | +## Running This Demo |
| 69 | + |
| 70 | +```bash |
| 71 | +pnpm --filter demo-advanced dev |
| 72 | +``` |
| 73 | + |
| 74 | +Watch the lifecycle log to see: |
| 75 | +- When actors are created |
| 76 | +- When cleanup happens (or doesn't!) |
| 77 | +- What gets logged when you stop/restart |
| 78 | + |
| 79 | +## Files in This Demo |
| 80 | + |
| 81 | +- `src/data-access/manual-actor.ts` - The complex lifecycle management code |
| 82 | +- `src/components/ManualLifecycleDemo.tsx` - UI showing the pattern |
| 83 | +- `src/App.tsx` - Entry point with cleanup in useEffect |
| 84 | + |
| 85 | +## Compare to the Main Demo |
| 86 | + |
| 87 | +The main demo (`apps/demo`) uses `interpret()` with Effect-Atom for a much simpler pattern: |
| 88 | + |
| 89 | +```typescript |
| 90 | +// Main demo approach - simple and safe |
| 91 | +const actorAtom = appRuntime |
| 92 | + .atom(interpret(machine)) |
| 93 | + .pipe(Atom.keepAlive); |
| 94 | + |
| 95 | +// That's it! No manual cleanup needed. |
| 96 | +``` |
| 97 | + |
| 98 | +## Conclusion |
| 99 | + |
| 100 | +**Use `interpret()` unless you have a very specific, measured need for `interpretManual()`.** |
| 101 | + |
| 102 | +The complexity and risk of memory leaks almost never justifies the small performance gain. |
0 commit comments