Skip to content

Conversation

@Catrya
Copy link
Member

@Catrya Catrya commented Sep 26, 2025

fix #277

  • Introduce startSessionTimeoutCleanupForRequestId() to handle orphan sessions when creating a new order without a response from Mostro within 10s
  • Add cancelSessionTimeoutCleanupForRequestId() to stop timers on any response to avoid false cleanups
  • Integrate cleanup logic in AddOrderNotifier:
    • Start timeout after submitting a new order
    • Cancel timeout when receiving response or disposing notifier
  • Extend SessionNotifier with deleteSessionByRequestId() for in-memory session cleanup
  • Increase action button timeout from 5s to 10s for consistency with cleanup window
  • Move timer cancellation from handleEvent() to subscribe() in AbstractMostroNotifier so cancellation applies reliably to all responses

Summary by CodeRabbit

  • Improvements

    • Unified 10s timeout protection for both order-taking and order-creation flows; submit timeout increased from 5s to 10s.
    • Starts a per-request timeout when submitting orders to guard against orphan temporary sessions.
  • Bug Fixes

    • Cancels timers on any response, successful confirmation, or when leaving screens to prevent stale timeout popups.
    • Ensures timers are cleared on notifier disposal.
  • Documentation

    • Updated architecture and docs to describe dual-session (orderId vs requestId) timeout behavior.

- Introduce startSessionTimeoutCleanupForRequestId() to handle orphan sessions when creating a new order without a response from Mostro within 10s
- Add cancelSessionTimeoutCleanupForRequestId() to stop timers on any response to avoid false cleanups
- Integrate cleanup logic in AddOrderNotifier:
  - Start timeout after submitting a new order
  - Cancel timeout when receiving response or disposing notifier
- Extend SessionNotifier with deleteSessionByRequestId() for in-memory session cleanup
- Increase action button timeout from 5s to 10s for consistency with cleanup window
- Move timer cancellation from handleEvent() to subscribe() in AbstractMostroNotifier so cancellation applies reliably to all responses
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 26, 2025

Walkthrough

Adds 10s request-scoped session timeout management alongside existing per-order timeouts: new start/cancel APIs for requestId, exposed per-order cancellation, integration into AddOrderNotifier lifecycle (start on submit, cancel on response/dispose), SessionNotifier gains deleteSessionByRequestId, and UI timeout increased to 10s.

Changes

Cohort / File(s) Summary
Session timeout utilities (order & request)
lib/features/order/notfiers/abstract_mostro_notifier.dart
Adds startSessionTimeoutCleanupForRequestId(int, Ref) and cancelSessionTimeoutCleanupForRequestId(int); exposes/renames cancelSessionTimeoutCleanup(String) as public; centralizes per-order timer cancellation on message receipt; manages shared _sessionTimeouts map; logs start/cancel and cancels timers in dispose.
Add order notifier lifecycle
lib/features/order/notfiers/add_order_notifier.dart
Starts 10s requestId-scoped timeout on submitOrder; cancels request timeout on any CantDo response and on successful confirmation; overrides dispose() to cancel active requestId timeout.
UI timeout parameter change
lib/features/order/widgets/action_buttons.dart
Increases MostroReactiveButton timeout from 5s to 10s.
Session notifier API expansion
lib/shared/notifiers/session_notifier.dart
Adds public deleteSessionByRequestId(int) to remove in-memory requestId→session mapping and emit updated state (no persistent deletion).
Docs / design updates
CLAUDE.md, docs/architecture/SESSION_AND_KEY_MANAGEMENT.md, docs/architecture/TIMEOUT_DETECTION_AND_SESSION_CLEANUP.md
Document dual-session model (temporary requestId vs permanent orderId), 10s cleanup timers, child-order flows, timer key conventions, and updated last-updated dates/semantics.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant UI as ActionButtons
  participant Add as AddOrderNotifier
  participant Abs as AbstractMostroNotifier
  participant Sess as SessionNotifier
  participant Mostro as Mostro Service

  User->>UI: Tap Submit
  UI->>Add: submitOrder(requestId)
  Add->>Abs: startSessionTimeoutCleanupForRequestId(requestId, ref) [start 10s timer]
  Add->>Mostro: publish/submitOrder(requestId)

  Note over Abs,Sess: If 10s elapse with no response
  Abs-->>Sess: deleteSessionByRequestId(requestId)
  Abs-->>UI: show timeout notification / navigate home
  Abs--x Mostro: (no response)

  Mostro-->>Add: Response (success or CantDo)
  Add->>Abs: cancelSessionTimeoutCleanupForRequestId(requestId)
  alt Response contains orderId
    Abs->>Abs: cancelSessionTimeoutCleanup(orderId) (per-order timer)
  end
  Add-->>UI: update state (confirmed or error handling)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • grunch

Poem

A rabbit taps the timer’s spring,
Ten hops I count for sessions’ wing.
If silence stays, I clear the trail,
Else I snap the clock—no panic, hail.
Carrots saved, the order sings. 🥕⏱️

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The PR title "feat: add orphan session cleanup for create orders with 10s timeout" accurately describes the main change in the pull request. The changeset introduces a new 10-second timeout mechanism specifically for order creation scenarios to clean up orphan sessions when no Mostro response is received, which is precisely what the title states. The title is concise, specific, and clearly conveys the primary objective of adding orphan session cleanup for create orders with a 10-second timeout window.
Linked Issues Check ✅ Passed The code changes directly address the objective from issue #277, which reports a "No session found for requestId" exception during order creation. The PR introduces startSessionTimeoutCleanupForRequestId() to manage orphan sessions during order creation, adds cancelSessionTimeoutCleanupForRequestId() to cancel timers when responses arrive, integrates cleanup logic into AddOrderNotifier with proper start/cancel/dispose lifecycle, and extends SessionNotifier with deleteSessionByRequestId() to remove in-memory sessions. These changes collectively ensure that request-specific sessions are reliably managed and cleaned up within a 10-second window, preventing the intermittent exception reported in the linked issue.
Out of Scope Changes Check ✅ Passed The changes to abstract_mostro_notifier.dart include modifications to the existing order-taking timeout mechanism (canceling per-order timers on message receipt, exposing cancelSessionTimeoutCleanup publicly) and action_buttons.dart increases the timeout from 5 to 10 seconds, both of which appear aligned with creating a consistent timeout strategy. The documentation updates in CLAUDE.md, SESSION_AND_KEY_MANAGEMENT.md, and TIMEOUT_DETECTION_AND_SESSION_CLEANUP.md comprehensively document the new dual-session timeout model. All changes appear directly related to implementing and documenting the orphan session cleanup mechanism for order creation with proper timer management, which is within the scope of fixing the session management issue reported in #277.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/orphan-session-create-order

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a97120b and fcd04ff.

📒 Files selected for processing (4)
  • CLAUDE.md (4 hunks)
  • docs/architecture/SESSION_AND_KEY_MANAGEMENT.md (3 hunks)
  • docs/architecture/TIMEOUT_DETECTION_AND_SESSION_CLEANUP.md (5 hunks)
  • lib/features/order/notfiers/abstract_mostro_notifier.dart (2 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
docs/**

📄 CodeRabbit inference engine (AGENTS.md)

Keep longer-form documentation, including architecture notes, under docs/

Files:

  • docs/architecture/SESSION_AND_KEY_MANAGEMENT.md
  • docs/architecture/TIMEOUT_DETECTION_AND_SESSION_CLEANUP.md
lib/**/*.dart

📄 CodeRabbit inference engine (CLAUDE.md)

lib/**/*.dart: Always use localized strings via S.of(context)!.keyName; avoid hardcoded user-facing text
Use const constructors where possible for immutability and performance
Check mounted before using BuildContext after async operations
Use S.of(context)!.keyName and pass BuildContext to methods needing localization

Files:

  • lib/features/order/notfiers/abstract_mostro_notifier.dart
lib/features/**

📄 CodeRabbit inference engine (AGENTS.md)

Place feature-specific Dart code under lib/features// (screens, providers, widgets)

Files:

  • lib/features/order/notfiers/abstract_mostro_notifier.dart
**/*.dart

📄 CodeRabbit inference engine (AGENTS.md)

**/*.dart: Format code with the Dart formatter (two-space indentation, trailing commas where beneficial)
Keep the analyzer (flutter_lints) at zero warnings across the codebase

Files:

  • lib/features/order/notfiers/abstract_mostro_notifier.dart
lib/features/**/*.dart

📄 CodeRabbit inference engine (AGENTS.md)

Name Riverpod providers as Provider or Notifier within their feature directory

Files:

  • lib/features/order/notfiers/abstract_mostro_notifier.dart
🧠 Learnings (7)
📚 Learning: 2025-06-26T15:03:23.529Z
Learnt from: chebizarro
PR: MostroP2P/mobile#127
File: lib/features/order/notfiers/abstract_mostro_notifier.dart:45-54
Timestamp: 2025-06-26T15:03:23.529Z
Learning: In AbstractMostroNotifier, state updates occur for all messages regardless of timestamp to hydrate the OrderNotifier from MostroStorage during sync, while handleEvent is only called for recent messages (within 60 seconds) to prevent re-triggering side effects like notifications and navigation for previously handled messages. This design prevents displaying stale notifications when the app is reopened or brought to the foreground.

Applied to files:

  • CLAUDE.md
  • docs/architecture/TIMEOUT_DETECTION_AND_SESSION_CLEANUP.md
  • lib/features/order/notfiers/abstract_mostro_notifier.dart
📚 Learning: 2025-09-22T18:48:23.369Z
Learnt from: CR
PR: MostroP2P/mobile#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-22T18:48:23.369Z
Learning: Applies to lib/main.dart : Configure timeago locales in `main.dart` with `timeago.setLocaleMessages()`

Applied to files:

  • CLAUDE.md
📚 Learning: 2025-09-22T18:48:23.369Z
Learnt from: CR
PR: MostroP2P/mobile#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-22T18:48:23.369Z
Learning: Applies to lib/features/**/notifiers/**/*.dart : Use Notifier pattern for complex state logic (authentication, order management) and place in `features/{feature}/notifiers/`

Applied to files:

  • docs/architecture/TIMEOUT_DETECTION_AND_SESSION_CLEANUP.md
  • lib/features/order/notfiers/abstract_mostro_notifier.dart
📚 Learning: 2025-07-20T23:33:17.689Z
Learnt from: Catrya
PR: MostroP2P/mobile#215
File: lib/features/order/notfiers/order_notifier.dart:0-0
Timestamp: 2025-07-20T23:33:17.689Z
Learning: In AbstractMostroNotifier, the handleEvent method is synchronous and returns void, not Future<void>. Do not suggest adding await to super.handleEvent() calls as this would cause compilation errors.

Applied to files:

  • lib/features/order/notfiers/abstract_mostro_notifier.dart
📚 Learning: 2025-05-06T15:49:55.079Z
Learnt from: chebizarro
PR: MostroP2P/mobile#74
File: lib/services/mostro_service.dart:97-103
Timestamp: 2025-05-06T15:49:55.079Z
Learning: In the Mostro protocol, an order cannot be canceled unless it has a valid orderId, so null checks on orderId during cancel operations are unnecessary.

Applied to files:

  • lib/features/order/notfiers/abstract_mostro_notifier.dart
📚 Learning: 2025-09-22T18:48:23.369Z
Learnt from: CR
PR: MostroP2P/mobile#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-22T18:48:23.369Z
Learning: Applies to lib/core/mostro_fsm.dart : Manage order state transitions via `MostroFSM`

Applied to files:

  • lib/features/order/notfiers/abstract_mostro_notifier.dart
📚 Learning: 2025-09-22T18:48:23.369Z
Learnt from: CR
PR: MostroP2P/mobile#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-22T18:48:23.369Z
Learning: Applies to lib/features/relays/relays_notifier.dart : Implement relay sync and blacklist operations in `RelaysNotifier` (`syncWithMostroInstance`, `removeRelayWithBlacklist`, `addRelayWithSmartValidation`)

Applied to files:

  • lib/features/order/notfiers/abstract_mostro_notifier.dart
🔇 Additional comments (10)
lib/features/order/notfiers/abstract_mostro_notifier.dart (3)

56-57: LGTM! Timer cancellation reliably applied to all responses.

The relocation of timer cancellation from handleEvent() to subscribe() ensures that any Mostro response—regardless of timestamp or action—will cancel the timeout timer. This prevents false cleanups and aligns with the PR's goal of reliable orphan session prevention.


416-457: LGTM! Request-scoped cleanup correctly namespaced.

The new startSessionTimeoutCleanupForRequestId and cancelSessionTimeoutCleanupForRequestId methods properly use the 'request:$requestId' key prefix (lines 418, 450) to avoid collisions with orderId-based timers. This addresses the concern raised in the previous review and ensures the two timer types operate in separate namespaces.

Based on past review comments.


438-446: LGTM! Public cancellation method enables external cleanup.

Exposing cancelSessionTimeoutCleanup as a public static method allows external notifiers (e.g., AddOrderNotifier) to cancel timers when appropriate. The method is safe, well-documented, and aligns with the dual-session timeout management model.

CLAUDE.md (2)

130-136: LGTM! Documentation accurately reflects implementation.

The Order Creation Protection section correctly documents the new startSessionTimeoutCleanupForRequestId() mechanism, including activation timing, cleanup behavior, and cancellation logic. This aligns with the implementation in abstract_mostro_notifier.dart.


150-150: LGTM! Documentation updates align with dual-session model.

The documentation accurately reflects:

  • Updated timer duration (30s → 10s)
  • Differentiated timer keys (orderId vs request:requestId)
  • Session type distinction (permanent vs temporary)
  • Current date for last update

All changes are consistent with the implementation.

Also applies to: 178-179, 184-185, 527-527

docs/architecture/TIMEOUT_DETECTION_AND_SESSION_CLEANUP.md (3)

981-1038: LGTM! Comprehensive documentation of order creation protection.

The Order Creation Protection section thoroughly documents:

  • Timer lifecycle (start on submit, cancel on response)
  • Integration with AddOrderNotifier
  • Cleanup behavior using deleteSessionByRequestId
  • Proper namespacing with 'request:$requestId' keys

All code snippets accurately reflect the implementation.


1121-1130: LGTM! Clear comparison table for dual-session model.

The comparison table effectively highlights the key differences between Order Creation and Order Taking:

  • Distinct timer methods and keys
  • Different cleanup approaches
  • Temporary vs permanent session handling
  • Clear use case separation

This table serves as a valuable reference for understanding the dual-session architecture.


934-934: LGTM! Documentation updates reflect dual-session architecture.

The updated sections correctly document:

  • 10-second timeout window for both scenarios
  • Differentiated handling between order creation and order taking
  • Dual timer key structure (orderId and 'request:requestId')

All changes align with the implementation and provide clear technical guidance.

Also applies to: 1083-1086, 1093-1094

docs/architecture/SESSION_AND_KEY_MANAGEMENT.md (2)

191-256: Excellent documentation of the dual-session architecture.

This section clearly differentiates temporary (requestId-based) and permanent (orderId-based) sessions, their lifecycle management, and cleanup mechanisms. The timer key strategy ('request:${requestId}' vs ${orderId}) is well-explained and prevents collisions. The documentation accurately reflects the orphan session prevention system introduced in this PR.


1159-1159: LGTM!

The last-updated date correctly reflects today's changes.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Tip

🧪 Early access (models): enabled

We are currently testing Sonnet 4.5 code review models, which should lead to better review quality. However, this model may result in higher noise levels in the review comments. Please disable the early access features if the noise level causes any inconvenience.

Note:

  • Public repositories are always opted into early access features.
  • You can enable or disable early access features from the CodeRabbit UI or by updating the CodeRabbit configuration file.

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: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 399ae2a and a97120b.

📒 Files selected for processing (4)
  • lib/features/order/notfiers/abstract_mostro_notifier.dart (2 hunks)
  • lib/features/order/notfiers/add_order_notifier.dart (4 hunks)
  • lib/features/order/widgets/action_buttons.dart (1 hunks)
  • lib/shared/notifiers/session_notifier.dart (1 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
lib/**/*.dart

📄 CodeRabbit inference engine (CLAUDE.md)

lib/**/*.dart: Always use localized strings via S.of(context)!.keyName; avoid hardcoded user-facing text
Use const constructors where possible for immutability and performance
Check mounted before using BuildContext after async operations
Use S.of(context)!.keyName and pass BuildContext to methods needing localization

Files:

  • lib/shared/notifiers/session_notifier.dart
  • lib/features/order/notfiers/add_order_notifier.dart
  • lib/features/order/widgets/action_buttons.dart
  • lib/features/order/notfiers/abstract_mostro_notifier.dart
lib/shared/**

📄 CodeRabbit inference engine (AGENTS.md)

Put shared utilities under lib/shared/

Files:

  • lib/shared/notifiers/session_notifier.dart
**/*.dart

📄 CodeRabbit inference engine (AGENTS.md)

**/*.dart: Format code with the Dart formatter (two-space indentation, trailing commas where beneficial)
Keep the analyzer (flutter_lints) at zero warnings across the codebase

Files:

  • lib/shared/notifiers/session_notifier.dart
  • lib/features/order/notfiers/add_order_notifier.dart
  • lib/features/order/widgets/action_buttons.dart
  • lib/features/order/notfiers/abstract_mostro_notifier.dart
lib/features/**

📄 CodeRabbit inference engine (AGENTS.md)

Place feature-specific Dart code under lib/features// (screens, providers, widgets)

Files:

  • lib/features/order/notfiers/add_order_notifier.dart
  • lib/features/order/widgets/action_buttons.dart
  • lib/features/order/notfiers/abstract_mostro_notifier.dart
lib/features/**/*.dart

📄 CodeRabbit inference engine (AGENTS.md)

Name Riverpod providers as Provider or Notifier within their feature directory

Files:

  • lib/features/order/notfiers/add_order_notifier.dart
  • lib/features/order/widgets/action_buttons.dart
  • lib/features/order/notfiers/abstract_mostro_notifier.dart
lib/features/**/{screens,providers,notifiers,widgets}/**/*.dart

📄 CodeRabbit inference engine (CLAUDE.md)

Follow feature-based organization: features/{feature}/{screens|providers|notifiers|widgets}/

Files:

  • lib/features/order/widgets/action_buttons.dart
🧠 Learnings (4)
📚 Learning: 2025-09-22T18:48:23.369Z
Learnt from: CR
PR: MostroP2P/mobile#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-22T18:48:23.369Z
Learning: Applies to lib/features/**/notifiers/**/*.dart : Use Notifier pattern for complex state logic (authentication, order management) and place in `features/{feature}/notifiers/`

Applied to files:

  • lib/features/order/notfiers/add_order_notifier.dart
  • lib/features/order/notfiers/abstract_mostro_notifier.dart
📚 Learning: 2025-06-26T15:03:23.529Z
Learnt from: chebizarro
PR: MostroP2P/mobile#127
File: lib/features/order/notfiers/abstract_mostro_notifier.dart:45-54
Timestamp: 2025-06-26T15:03:23.529Z
Learning: In AbstractMostroNotifier, state updates occur for all messages regardless of timestamp to hydrate the OrderNotifier from MostroStorage during sync, while handleEvent is only called for recent messages (within 60 seconds) to prevent re-triggering side effects like notifications and navigation for previously handled messages. This design prevents displaying stale notifications when the app is reopened or brought to the foreground.

Applied to files:

  • lib/features/order/notfiers/add_order_notifier.dart
  • lib/features/order/notfiers/abstract_mostro_notifier.dart
📚 Learning: 2025-06-04T19:35:20.209Z
Learnt from: chebizarro
PR: MostroP2P/mobile#110
File: test/notifiers/take_order_notifier_test.dart:72-74
Timestamp: 2025-06-04T19:35:20.209Z
Learning: MostroService methods like takeBuyOrder() and takeSellOrder() return Future<void> and trigger side effects through other mechanisms rather than direct return values. When testing these methods, focus on verifying method calls and testing state changes through the provider system rather than mocking return values.

Applied to files:

  • lib/features/order/notfiers/add_order_notifier.dart
📚 Learning: 2025-09-22T18:48:23.369Z
Learnt from: CR
PR: MostroP2P/mobile#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-22T18:48:23.369Z
Learning: Applies to lib/features/relays/relays_notifier.dart : Implement relay sync and blacklist operations in `RelaysNotifier` (`syncWithMostroInstance`, `removeRelayWithBlacklist`, `addRelayWithSmartValidation`)

Applied to files:

  • lib/features/order/notfiers/abstract_mostro_notifier.dart
⏰ 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). (1)
  • GitHub Check: build
🔇 Additional comments (6)
lib/shared/notifiers/session_notifier.dart (1)

190-196: Fix return type mismatch in deleteSessionByRequestId

Declaring the method as Future<void> without marking it async (or explicitly returning a Future) produces a compile-time error: the function ends without returning a Future, so the analyzer reports “This function has a return type of ‘Future’ but doesn’t end with a return statement.” Please add async (or return Future.value()) so callers awaiting this method continue to compile.

-  Future<void> deleteSessionByRequestId(int requestId) async {
+  Future<void> deleteSessionByRequestId(int requestId) async {
     _requestIdToSession.remove(requestId);
     // Note: No storage deletion - these are temporary sessions in memory only
     _emitState();
   }

Likely an incorrect or invalid review comment.

lib/features/order/notfiers/add_order_notifier.dart (4)

43-45: LGTM: Cancelling on CantDo avoids stray cleanups.

Clearing the per-request timeout as soon as any CantDo arrives keeps the orphan-session cleanup from firing after we already handled the response.


64-66: LGTM: Success path clears timeout.

Dropping the timer as soon as we confirm the order ensures no lingering cleanup will race with the success flow.


90-92: LGTM: Starting the 10 s watchdog on submit.

Kicking off the per-request timer right after opening the session matches the new orphan cleanup contract.


117-120: LGTM: Dispose path tidies timers.

Canceling the outstanding request timer during dispose keeps background cleanups from firing after this notifier is gone.

lib/features/order/widgets/action_buttons.dart (1)

52-52: LGTM: UI timeout matches backend window.

Extending the reactive button timeout to 10 s keeps the UX aligned with the new session cleanup horizon.

Copy link
Member

@grunch grunch left a comment

Choose a reason for hiding this comment

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

utACK

@grunch grunch merged commit 006a04e into main Oct 1, 2025
2 checks passed
@grunch grunch deleted the fix/orphan-session-create-order branch October 1, 2025 14:08
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.

Error when try to create a new order (low-frequency )

3 participants