Repository: slawlor/ractor (rust)

Issue:
ActorRef::get_children() clears children record from supervision tree
**Describe the bug**

I'm not sure if this is intentional, but it's definitely a footgun. If I call `some_actor.get_children()` twice, then the second time returns an empty Vec. The children actors are still running and points to the original parent (half unlinked).

**To Reproduce**
Steps to reproduce the behavior:
1. Create an actor tree
2. On root actor, call `root.get_children()`
3. `assert_eq!(first_children_len, second_children_len)`
4. See error

**Expected behavior**

There should be a  non-destructive way to retrieve the list of children actors.

**Additional context**

https://github.com/slawlor/ractor/blob/main/ractor/src/actor/supervision.rs#L140

Pull request description:
fix: get_children should not break supervision tree integrity
This fixes #310 

Please suggest where and what tests I can add.

Patch:
diff --git a/ractor/src/actor/supervision.rs b/ractor/src/actor/supervision.rs
index 06773dd..8b6ef63 100644
--- a/ractor/src/actor/supervision.rs
+++ b/ractor/src/actor/supervision.rs
@@ -57,7 +57,11 @@ impl SupervisionTree {
     /// from the supervision tree since the supervisor is shutting down
     /// and can't deal with superivison events anyways
     pub(crate) fn terminate_all_children(&self) {
-        let cells = self.get_children();
+        let mut guard = self.children.lock().unwrap();
+        let cells = guard.values().cloned().collect::<Vec<_>>();
+        guard.clear();
+        // drop the guard to not deadlock on double-link
+        drop(guard);
         for cell in cells {
             cell.terminate();
             cell.clear_supervisor();
@@ -134,13 +138,10 @@ impl SupervisionTree {
         }
     }
 
+    /// Return all linked children
     pub(crate) fn get_children(&self) -> Vec<ActorCell> {
-        let mut guard = self.children.lock().unwrap();
-        let cells = guard.iter().map(|(_, a)| a.clone()).collect::<Vec<_>>();
-        guard.clear();
-        // drop the guard to not deadlock on double-link
-        drop(guard);
-        cells
+        let guard = self.children.lock().unwrap();
+        guard.values().cloned().collect()
     }
 
     /// Send a notification to the supervisor.


Test patch:
diff --git a/ractor/src/actor/tests/supervisor.rs b/ractor/src/actor/tests/supervisor.rs
index ff5f45f..ad1e2e6 100644
--- a/ractor/src/actor/tests/supervisor.rs
+++ b/ractor/src/actor/tests/supervisor.rs
@@ -1557,6 +1557,9 @@ async fn draining_children_will_shutdown_parent_too() {
     // notify the parent (supervisor) and take that down too
     supervisor_ref.drain_children();
 
+    // children were not unlinked by draining them (fixed from #310)
+    assert!(!supervisor_ref.get_children().is_empty());
+
     // Wait for exit
     s_handle.await.unwrap();
     c_handle.await.unwrap();