Skip to content
This repository has been archived by the owner on Sep 27, 2024. It is now read-only.

Add force option to mailbox.put #25

Closed
wants to merge 2 commits into from
Closed

Conversation

ntkme
Copy link
Contributor

@ntkme ntkme commented Jul 11, 2024

This PR adds an option to force overwrite the message already in Mailbox. This is necessary for dart-sass to properly shutdown. As dart-sass is being shutting down, we send a zero length message to the worker isolate to indicate that the main isolate is planning to shutdown, that no further work shall be done. Once the worker isolate received the message and detected that the length is zero, it will break out of the loop and stop the work, in order to prevent it from running another mailbox.take and getting stuck.

https://github.com/sass/dart-sass/blob/d4b19397c493adb6e518ed5344913aa2615c11f6/lib/src/embedded/reusable_isolate.dart#L119-L129

  /// Shuts down the isolate.
  void kill() {
    _isolate.kill();
    _receivePort.close();

    // If the isolate is blocking on [Mailbox.take], it won't even process a
    // kill event, so we send an empty message to make sure it wakes up.
    try {
      _mailbox.put(Uint8List(0));
    } on StateError catch (_) {}
  }

This currently causes an issue that dart vm would lock up if sending of the empty message fails due to Mailbox already has content, and thus causes the worker isolate to not shutting down properly if it gets a non-empty message and quickly loop again to wait on the next message before the kill event is processed: sass/dart-sass#2278

I've tested locally that this PR together with the following patch in dart-sass fixes the issue: sass/dart-sass#2279

diff --git a/lib/src/embedded/reusable_isolate.dart b/lib/src/embedded/reusable_isolate.dart
index 0ed9eec8..304cb3de 100644
--- a/lib/src/embedded/reusable_isolate.dart
+++ b/lib/src/embedded/reusable_isolate.dart
@@ -123,9 +123,7 @@ class ReusableIsolate {
 
     // If the isolate is blocking on [Mailbox.take], it won't even process a
     // kill event, so we send an empty message to make sure it wakes up.
-    try {
-      _mailbox.put(Uint8List(0));
-    } on StateError catch (_) {}
+    _mailbox.put(Uint8List(0), force: true);
   }
 }
 

@ntkme
Copy link
Contributor Author

ntkme commented Jul 11, 2024

An alternative implementation to a force put is to add a mailbox.close method which change the mailbox to a new state _stateClosed and notify. mailbox.take will throw a StateError if the mailbox changed to closed state. In dart-sass we just interrupt the loop on StateError, instead of based on an empty message. As long as we have reliable way to deliver the signal that we need to close regardless of whether mailbox is currently filled or not, we will be able to address the problem.

@mraleph @nex3 I've put up PR #26 as an alternative. Any preference on the implementation?

@ntkme ntkme mentioned this pull request Jul 11, 2024
@nex3
Copy link

nex3 commented Jul 11, 2024

I have no particular preference.

@ntkme
Copy link
Contributor Author

ntkme commented Jul 11, 2024

I think #26 might be slightly better, as the logic to free the buffer of dropped message looks a bit messy in this PR.

@ntkme
Copy link
Contributor Author

ntkme commented Jul 12, 2024

Closing in favor of #26.

@ntkme ntkme closed this Jul 12, 2024
@ntkme ntkme deleted the force-put branch July 12, 2024 15:37
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Development

Successfully merging this pull request may close these issues.

2 participants