Skip to content

fix(listener): improve error handling in session lifecycle#1924

Merged
yujonglee merged 1 commit intomainfrom
devin/1764157103-listener-error-handling
Nov 26, 2025
Merged

fix(listener): improve error handling in session lifecycle#1924
yujonglee merged 1 commit intomainfrom
devin/1764157103-listener-error-handling

Conversation

@yujonglee
Copy link
Contributor

@yujonglee yujonglee commented Nov 26, 2025

Summary

Implements error handling improvements for the listener plugin based on code review feedback. The changes make the session lifecycle more robust by treating certain failures as non-fatal:

  1. ext.rs: Replace .unwrap() on SessionEvent::emit() with error logging - prevents panics if Tauri fails to emit events (e.g., window closed, runtime shutting down)

  2. recorder.rs: Don't treat WAV-to-OGG encode failures as fatal in post_stop - keeps the WAV file as fallback instead of triggering supervisor restarts during shutdown

  3. listener.rs:

    • Treat StreamResponse emit failures as non-fatal (log instead of propagate error)
    • Break the websocket stream loop if send_message to the actor fails - prevents task leaks when the actor is killed/panicked

Review & Testing Checklist for Human

  • Verify that logging errors instead of panicking on event emit failures is acceptable for your observability needs
  • Confirm that keeping WAV files when OGG encoding fails (instead of restarting the recorder) is the desired fallback behavior
  • Test a session start/stop cycle to ensure events are still emitted correctly in the happy path
  • Consider testing with a closed window or during app shutdown to verify the non-fatal error handling works as expected

Notes

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

These changes address issues 2.1, 2.2, 2.3, and 2.4 from the code review.

- Remove .unwrap() on SessionEvent::emit in ext.rs - treat as non-fatal
- Don't treat Recorder's encode failures as fatal in post_stop
- Don't treat UI-emit failures in ListenerActor as fatal
- Make Listener's websocket tasks bail if sending ListenerMsg fails

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

🤖 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 Nov 26, 2025

Deploy Preview for hyprnote ready!

Name Link
🔨 Latest commit 723689d
🔍 Latest deploy log https://app.netlify.com/projects/hyprnote/deploys/6926e80ae2e90400084738d9
😎 Deploy Preview https://deploy-preview-1924--hyprnote.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify
Copy link

netlify bot commented Nov 26, 2025

Deploy Preview for hyprnote-storybook ready!

Name Link
🔨 Latest commit 723689d
🔍 Latest deploy log https://app.netlify.com/projects/hyprnote-storybook/deploys/6926e80a14ac490008520fda
😎 Deploy Preview https://deploy-preview-1924--hyprnote-storybook.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 26, 2025

📝 Walkthrough

Walkthrough

Error handling refactoring across listener plugin components replaces crash-prone patterns (unwrap, error propagation) with explicit error logging and graceful continuation in StreamResponse emission, encoding operations, and SessionEvent emission paths.

Changes

Cohort / File(s) Summary
Error handling refactoring in listener plugin
plugins/listener/src/actors/listener.rs, plugins/listener/src/actors/recorder.rs, plugins/listener/src/ext.rs
StreamResponse sends in ListenerActor now guard for emission errors, log warnings, and break loops on failure instead of propagating. Encoding errors in RecorderActor post_stop are logged and swallowed; temporary WAV is kept as fallback on encoding failure. SessionEvent emissions in ext.rs replace unwrap() calls with if-let error guards that log errors and continue execution.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Specific attention areas:
    • plugins/listener/src/actors/listener.rs: Verify the guarded-send pattern correctly breaks loops and doesn't mask legitimate error conditions that should halt processing.
    • plugins/listener/src/actors/recorder.rs: Confirm that keeping WAV as fallback on encoding failure is the intended behavior and doesn't create unintended side effects or data retention issues.
    • plugins/listener/src/ext.rs: Ensure all three SessionEvent emission paths (RunningActive, Finalizing, Inactive) follow consistent error handling and logging conventions.

Possibly related PRs

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: improving error handling in the session lifecycle of the listener plugin.
Description check ✅ Passed The description is directly related to the changeset, providing a detailed summary of error handling improvements across three files (ext.rs, recorder.rs, listener.rs).
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch devin/1764157103-listener-error-handling

Tip

📝 Customizable high-level summaries are now available in beta!

You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.

  • Provide your own instructions using the high_level_summary_instructions setting.
  • Format the summary however you like (bullet lists, tables, multi-section layouts, contributor stats, etc.).
  • Use high_level_summary_in_walkthrough to move the summary from the description to the walkthrough section.

Example instruction:

"Divide the high-level summary into five sections:

  1. 📝 Description — Summarize the main change in 50–60 words, explaining what was done.
  2. 📓 References — List relevant issues, discussions, documentation, or related PRs.
  3. 📦 Dependencies & Requirements — Mention any new/updated dependencies, environment variable changes, or configuration updates.
  4. 📊 Contributor Summary — Include a Markdown table showing contributions:
    | Contributor | Lines Added | Lines Removed | Files Changed |
  5. ✔️ Additional Notes — Add any extra reviewer context.
    Keep each section concise (under 200 words) and use bullet or numbered lists for clarity."

Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (3)
plugins/listener/src/ext.rs (1)

114-120: Guarded SessionEvent emits align with the goal of avoiding panics

Wrapping the SessionEvent::* emits in if let Err(error) and logging instead of unwrapping gives you best‑effort notifications without taking down the session when the Tauri event layer misbehaves. Control flow in both start_session and stop_session remains sensible.

If you want richer observability later, consider adding session_id into the log context so failures can be correlated to specific sessions.

Please double‑check that the tauri/tauri_specta Event::emit error conditions you care about are indeed non‑fatal (e.g., closed window) so logging‑and‑continue is acceptable for your UX guarantees.

Also applies to: 146-148, 165-167

plugins/listener/src/actors/recorder.rs (1)

161-179: Encoding errors are now non‑fatal; confirm whether rename/remove should behave similarly

The new match around encode_wav_to_vorbis_file nicely logs failures and preserves the WAV as a fallback without failing the actor, which matches the comment intent.

Note that std::fs::rename(&temp_ogg_path, &st.ogg_path)? and std::fs::remove_file(&st.wav_path)? still propagate IO errors via ?. That means filesystem issues at this point can still cause post_stop to return an error. If the broader goal is “shutdown should not fail just because finalization/cleanup had issues,” you might want to treat these similarly (log + best‑effort) rather than bubbling them.

Please verify whether your supervision strategy expects post_stop to succeed even on finalization/cleanup IO hiccups; if not, current behavior is fine, otherwise consider matching and logging instead of ?.

plugins/listener/src/actors/listener.rs (1)

530-533: Breaking stream loops on send_message failure is reasonable; confirm ractor semantics

In both the finalize path and the main stream loop, you now treat myself.send_message(ListenerMsg::StreamResponse(response)).is_err() as a signal to log and break out of the loop. That’s a sensible way to stop the RX task once the actor is no longer able to receive messages, and it avoids panics.

This relies on ActorRef::send_message only erroring when the actor is gone or shutting down. If ractor can also return errors for transient reasons (e.g., mailbox full with an error instead of backpressure), this would prematurely terminate the stream. If it only fails on shutdown, the new behavior is spot on.

Please confirm ractor’s send_message error semantics. If you find any non‑terminal cases, consider distinguishing them (e.g., via error variants) so you only break the loop when the actor is truly gone.

Also applies to: 563-566

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 41f0f76 and 723689d.

📒 Files selected for processing (3)
  • plugins/listener/src/actors/listener.rs (3 hunks)
  • plugins/listener/src/actors/recorder.rs (1 hunks)
  • plugins/listener/src/ext.rs (3 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: plyght
Repo: fastrepl/hyprnote PR: 921
File: plugins/location-connectivity/src/error.rs:1-41
Timestamp: 2025-06-06T16:31:46.457Z
Learning: In the location-connectivity plugin (plugins/location-connectivity/), comprehensive error handling via LocationConnectivityError is necessary despite the "no error handling" guideline, as the plugin performs system-level operations (WiFi detection, persistent storage) that require proper error propagation to the frontend.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: Redirect rules - hyprnote
  • GitHub Check: Header rules - hyprnote
  • GitHub Check: Pages changed - hyprnote
  • GitHub Check: fmt
  • GitHub Check: ci (linux, depot-ubuntu-24.04-8)
  • GitHub Check: ci (linux, depot-ubuntu-22.04-8)
  • GitHub Check: ci (macos, depot-macos-14)
🔇 Additional comments (1)
plugins/listener/src/actors/listener.rs (1)

129-136: Guarding StreamResponse event emission prevents crashes on frontend failures

Switching SessionEvent::StreamResponse emission to if let Err(error) with a structured log means transcript streaming won’t panic the listener if the Tauri event emission fails (e.g., window gone). That’s consistent with the rest of the PR’s error‑handling strategy.

If you ever see these logs frequently in production, it might be worth adding counters/metrics so you can distinguish one‑off UI issues from systemic event emission problems.

Please briefly confirm that, for your UX, it’s acceptable to keep the listener actor alive even when event emission starts failing (i.e., you don’t need to stop the session in that case).

@yujonglee yujonglee merged commit 8d368a5 into main Nov 26, 2025
15 checks passed
@yujonglee yujonglee deleted the devin/1764157103-listener-error-handling branch November 26, 2025 11:54
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