Skip to content

Replace ractor_supervisor with custom SessionActor for per-actor-type supervision#3958

Merged
yujonglee merged 5 commits intomainfrom
devin/1771042788-session-actor-supervision
Feb 14, 2026
Merged

Replace ractor_supervisor with custom SessionActor for per-actor-type supervision#3958
yujonglee merged 5 commits intomainfrom
devin/1771042788-session-actor-supervision

Conversation

@devin-ai-integration
Copy link
Contributor

@devin-ai-integration devin-ai-integration bot commented Feb 14, 2026

Replace ractor_supervisor with custom SessionActor supervision

Summary

Replaces the ractor_supervisor::Supervisor (RestForOne strategy) with a custom SessionActor that implements ractor::Actor directly, enabling per-actor-type supervision. This is the core fix for the bug where recording stops when STT (transcription) fails.

Key behavioral change: When ListenerActor dies (STT failure), the session enters "degraded mode" — recording and audio capture continue uninterrupted. Previously, RestForOne would kill RecorderActor too.

What changed:

  • session/mod.rs: Replaced Supervisor + ChildSpec pattern with SessionActor implementing Actor trait. handle_supervisor_evt routes events by child type: Listener death → degraded mode; Source/Recorder death → restart with limits (3 in 15s), then meltdown. Graceful shutdown is handled via SessionMsg::Shutdown which stops children in order (Recorder first, with wait for WAV finalization, then Source/Listener) and sets shutting_down flag to suppress supervision restarts during teardown.
  • events.rs: SessionLifecycleEvent::Active now carries an optional DegradedError to notify the frontend of degraded state.
  • root.rs: Updated Active event emission to pass error: None. stop_session_impl now sends SessionMsg::Shutdown to the SessionActor instead of directly stopping children by name. ActorTerminated handler now parses DegradedError from the session stop reason and propagates it to emit_session_ended.
  • Cargo.toml: Removed ractor-supervisor dependency.

Updates since last revision

Addressed review findings:

  1. Restart limit checked before spawn: Moved record_restart() to before Actor::spawn_linked() in try_restart_source and try_restart_recorder. Previously the actor was spawned first, and if the limit was exceeded the new actor was already running but never stored — an orphaned actor leak.
  2. 50ms backoff delay before respawn: Added tokio::time::sleep(50ms) before each spawn_linked in the restart paths. Without this, rapid respawns hit name collisions in ractor's actor registry (the old supervisor had a 500ms backoff).
  3. Root propagates DegradedError on session end: root.rs ActorTerminated handler now parses DegradedError JSON from the session actor's stop reason and passes it to emit_session_ended, instead of always passing None.
  4. #[derive(Debug)] on SessionMsg: Added missing derive required by ractor's Message trait.

Review & Testing Checklist for Human

  • 50ms backoff may be insufficient: The old code used 500ms. Verify 50ms is enough for ractor's registry to deregister actor names, especially under load. If restarts still fail with name collisions, increase the delay.

  • identify_child uses cell-ID matching: When a child terminates, its cell is cleared from state, then restart is attempted. If the new actor dies quickly and the old cell's termination event arrives late, identify_child won't match it (returns None → silently ignored). Name-based identification would be more robust but is lower priority.

  • ActorRef<SessionMsg> cast from ActorCell: In stop_session_impl, let session_ref: ActorRef<SessionMsg> = supervisor.clone().into() performs an unchecked type cast. This relies on state.supervisor always being the SessionActor cell. Confirm ractor's into() behavior — if the cell is somehow not a SessionActor, the cast(Shutdown) would silently fail or panic.

  • Test manually: Start a recording session, then simulate STT failure (e.g., disconnect network, use invalid API key). Verify:

    • Recording continues (WAV file keeps growing)
    • Frontend receives Active event with error field populated
    • Session can still be stopped gracefully (no double WAV finalization, no spurious restarts logged)

Notes

  • The listener_degraded field in SessionState is set but never read — it's placeholder state for future use.
  • stop_actor_by_name_and_wait in lifecycle.rs is now unused (compiler warning). Can be removed in a follow-up.
  • Frontend TypeScript types will auto-regenerate via specta, but frontend code doesn't yet display degraded mode info.
  • cargo check -p tauri-plugin-listener passes.

Link to Devin run: https://app.devin.ai/sessions/ab6b741af4114e40ba11334c08eaf56f
Requested by: @yujonglee


Open with Devin

…r-actor-type supervision

Co-Authored-By: yujonglee <yujonglee.dev@gmail.com>
@devin-ai-integration
Copy link
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR that start with 'DevinAI' or '@devin'.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

@netlify
Copy link

netlify bot commented Feb 14, 2026

Deploy Preview for hyprnote canceled.

Name Link
🔨 Latest commit 93a3b73
🔍 Latest deploy log https://app.netlify.com/projects/hyprnote/deploys/69903fe65de2630008fb991c

@netlify
Copy link

netlify bot commented Feb 14, 2026

Deploy Preview for hyprnote-storybook canceled.

Name Link
🔨 Latest commit 93a3b73
🔍 Latest deploy log https://app.netlify.com/projects/hyprnote-storybook/deploys/69903fe68d34880008aff1a6

Copy link
Contributor Author

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 potential issue.

View 6 additional findings in Devin Review.

Open in Devin Review

…, move restart counter after successful spawn

Co-Authored-By: yujonglee <yujonglee.dev@gmail.com>
Copy link
Contributor Author

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 new potential issue.

View 9 additional findings in Devin Review.

Open in Devin Review

…y, propagate DegradedError, add Debug to SessionMsg

Co-Authored-By: yujonglee <yujonglee.dev@gmail.com>
Copy link
Contributor Author

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 3 new potential issues.

View 12 additional findings in Devin Review.

Open in Devin Review

@fastrepl fastrepl deleted a comment from devin-ai-integration bot Feb 14, 2026
…er in meltdown, fallback stop reason

Co-Authored-By: yujonglee <yujonglee.dev@gmail.com>
Copy link
Contributor Author

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 potential issue.

View 5 additional findings in Devin Review.

Open in Devin Review

Copy link
Contributor Author

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 new potential issues.

View 9 additional findings in Devin Review.

Open in Devin Review

@yujonglee yujonglee merged commit f412fe5 into main Feb 14, 2026
20 checks passed
@yujonglee yujonglee deleted the devin/1771042788-session-actor-supervision branch February 14, 2026 09:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant