Skip to main content

Response Timeout

Request-response patterns need timeouts. Without them, a single unresponsive Actor can freeze the entire application.

The Pattern: Request-Response

┌─────────────────────────────────────────────────────────────────┐
│  ONESHOT CHANNEL: REQUEST-RESPONSE                              │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  IPC Handler (Tauri command)              SessionActor          │
│       │                                        │                │
│       │   1. Create oneshot channel            │                │
│       │      (for response)                    │                │
│       │                                        │                │
│       │   ════════ Command ════════════▶       │                │
│       │       (includes response channel)      │                │
│       │                                        │                │
│       │   2. Wait for response                 │   3. Process   │
│       │      ⏳ WAITING...                     │   4. Send OK   │
│       │                                        │                │
│       │   ◀════════ Response ═══════════       │                │
│       │                                        │                │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

The Problem: Infinite Wait

┌─────────────────────────────────────────────────────────────────┐
│  BUG: NO TIMEOUT                                                │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  BEFORE FIX:                                                    │
│  ━━━━━━━━━━━━                                                   │
│                                                                 │
│  1. Send command to Actor                                       │
│  2. Wait for response                                           │
│     ← NO TIMEOUT!                                               │
│     ← If Actor doesn't respond → wait FOREVER                   │
│                                                                 │
│  ─────────────────────────────────────────────────────────────  │
│                                                                 │
│  FAILURE SCENARIO 1: Actor Crash                                │
│  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━                                │
│                                                                 │
│  IPC Handler                          SessionActor              │
│       │                                    │                    │
│       │ ──── CreateSession ────────▶       │                    │
│       │                                   💥 panic!             │
│       │                                    │                    │
│       │    ⏳ waiting...                  ✖ (dead)              │
│       │    ⏳ waiting...                                        │
│       │    ⏳ FOREVER                                           │
│       │                                                         │
│  Result: IPC blocked, user sees frozen UI                       │
│                                                                 │
│  ─────────────────────────────────────────────────────────────  │
│                                                                 │
│  FAILURE SCENARIO 2: Actor Busy                                 │
│  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━                                 │
│                                                                 │
│  IPC Handler                          SessionActor              │
│       │                                    │                    │
│       │ ──── CreateSession ────────▶       │                    │
│       │                                   🔄 (stuck)            │
│       │    ⏳ waiting...                  🔄 (never processes)  │
│       │    ⏳ waiting...                  🔄                    │
│       │    ⏳ FOREVER                     🔄                    │
│       │                                                         │
│  Result: IPC blocked indefinitely                               │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

The Fix: Timeout Wrapper

┌─────────────────────────────────────────────────────────────────┐
│  TIMEOUT ERROR CHAIN                                            │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  timeout(10 seconds, wait_for_response)                         │
│       │                                                         │
│       ├── SUCCESS ────────────────▶ Response received           │
│       │                                                         │
│       ├── TIMEOUT ────────────────▶ Error: "timeout"            │
│       │                            (after 10 seconds)           │
│       │                                                         │
│       └── CHANNEL CLOSED ─────────▶ Error: "Actor dropped"      │
│                                    (Actor died)                 │
│                                                                 │
│  ═══════════════════════════════════════════════════════════    │
│                                                                 │
│  AFTER FIX:                                                     │
│  ━━━━━━━━━━━                                                    │
│                                                                 │
│  1. Send command to Actor                                       │
│  2. Wait for response WITH 10 SECOND TIMEOUT                    │
│  3. If timeout → return error to frontend                       │
│  4. User sees error message, app stays responsive               │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

Functions Protected (8 Total)

┌─────────────────────────────────────────────────────────────────┐
│  FUNCTIONS WITH TIMEOUT APPLIED                                 │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  +------------------------+------------------------------------+│
│  | Function               | Description                        |│
│  +------------------------+------------------------------------+│
│  | create_session         | Create new terminal session        |│
│  | broadcast_to_visible   | Send data to visible sessions      |│
│  | resize_session         | Resize terminal window             |│
│  | close_session          | Close terminal session             |│
│  | kill_session           | Force kill session                 |│
│  | terminal_search        | Search in terminal buffer          |│
│  | pty_pause_native       | Pause PTY output                   |│
│  | pty_resume_native      | Resume PTY output                  |│
│  +------------------------+------------------------------------+│
│                                                                 │
│  All 8 functions follow the same pattern:                       │
│                                                                 │
│  1. Create oneshot channel                                      │
│  2. Send command to Actor                                       │
│  3. Wait for response WITH 10 SECOND TIMEOUT                    │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

Why 10 Seconds?

┌─────────────────────────────────────────────────────────────────┐
│  TIMEOUT VALUE ANALYSIS                                         │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  NORMAL RESPONSE TIME:                                          │
│  ━━━━━━━━━━━━━━━━━━━━━                                          │
│                                                                 │
│  Typical Actor response: < 1ms                                  │
│                                                                 │
│  ┌──────┬──────┬──────┬──────┬──────┬──────┐                    │
│  │ <1ms │      │      │      │      │ 10s  │                    │
│  └──────┴──────┴──────┴──────┴──────┴──────┘                    │
│  normal                             timeout                     │
│  │◀──────────────────────────────────▶│                         │
│             10,000x safety margin                               │
│                                                                 │
│  ─────────────────────────────────────────────────────────────  │
│                                                                 │
│  WHY 10 SECONDS?                                                │
│  ━━━━━━━━━━━━━━━                                                │
│                                                                 │
│  +---------------------+---------------------------------------+│
│  | Value               | Trade-off                             |│
│  +---------------------+---------------------------------------+│
│  | 1 second            | May timeout during heavy load         |│
│  |                     | (false positive)                      |│
│  +---------------------+---------------------------------------+│
│  | 5 seconds           | Reasonable but tight                  |│
│  +---------------------+---------------------------------------+│
│  | 10 seconds ✓        | Safe margin, still responsive         |│
│  +---------------------+---------------------------------------+│
│  | 30 seconds          | User waits too long before error      |│
│  +---------------------+---------------------------------------+│
│  | 60 seconds          | Unacceptable UX                       |│
│  +---------------------+---------------------------------------+│
│                                                                 │
│  10 seconds is the "Goldilocks" value:                          │
│  Not too short (false positives), not too long (bad UX)         │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

Defense in Depth

┌─────────────────────────────────────────────────────────────────┐
│  TIMEOUT + PASSTHROUGH = COMPLETE SAFETY                        │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  TWO COMPLEMENTARY PROTECTIONS:                                 │
│                                                                 │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                                                         │    │
│  │   1. PASSTHROUGH DESIGN                                 │    │
│  │      ────────────────────                               │    │
│  │      • Actor doesn't die (OOM impossible, no panic)     │    │
│  │      • Probability of needing timeout: ~0.001%          │    │
│  │                                                         │    │
│  │   2. TIMEOUT                                            │    │
│  │      ────────                                           │    │
│  │      • If Actor somehow fails, IPC doesn't hang         │    │
│  │      • Graceful error handling                          │    │
│  │      • Defense in depth                                 │    │
│  │                                                         │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                 │
│  ═══════════════════════════════════════════════════════════    │
│                                                                 │
│  DEFENSE IN DEPTH:                                              │
│                                                                 │
│  Layer 1: Passthrough prevents Actor death                      │
│           → Timeout rarely triggers                             │
│                                                                 │
│  Layer 2: Timeout catches edge cases                            │
│           → Even if Actor fails, app doesn't freeze             │
│                                                                 │
│  Result: System is robust against all failure modes             │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

Summary

┌─────────────────────────────────────────────────────────────────┐
│  KEY TAKEAWAYS                                                  │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  1. THE BUG                                                     │
│     Oneshot channels without timeout can block forever          │
│     → Application appears frozen                                │
│                                                                 │
│  2. THE FIX                                                     │
│     Wrap all response waits with timeout()                      │
│     → 10 second timeout for all 8 IPC handlers                  │
│                                                                 │
│  3. WHY 10 SECONDS                                              │
│     Normal response: < 1ms                                      │
│     10s = 10,000x safety margin                                 │
│     → Catches real failures, avoids false positives             │
│                                                                 │
│  4. DEFENSE IN DEPTH                                            │
│     Passthrough design: Actor rarely fails                      │
│     Timeout: Catches the rare failure gracefully                │
│     → Combined = robust system                                  │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘