@@ -964,13 +964,30 @@ impl<A: Actor> Instance<A> {
964
964
965
965
let result = self . run_actor_tree ( & mut actor, actor_loop_receivers) . await ;
966
966
967
- let actor_status = match result {
968
- Ok ( _) => ActorStatus :: Stopped ,
969
- Err ( err) => ActorStatus :: Failed ( err. to_string ( ) ) ,
967
+ let ( actor_status, event) = match result {
968
+ Ok ( _) => ( ActorStatus :: Stopped , None ) ,
969
+ Err ( ActorError {
970
+ kind : ActorErrorKind :: UnhandledSupervisionEvent ( event) ,
971
+ ..
972
+ } ) => ( event. actor_status . clone ( ) , Some ( event) ) ,
973
+ Err ( err) => (
974
+ ActorStatus :: Failed ( err. to_string ( ) ) ,
975
+ Some ( ActorSupervisionEvent {
976
+ actor_id : self . cell . actor_id ( ) . clone ( ) ,
977
+ actor_status : ActorStatus :: Failed ( err. to_string ( ) ) ,
978
+ message_headers : None ,
979
+ caused_by : None ,
980
+ } ) ,
981
+ ) ,
970
982
} ;
971
983
972
- let result = self . cell . maybe_unlink_parent ( ) ;
973
- if let Some ( parent) = result {
984
+ if let Some ( parent) = self . cell . maybe_unlink_parent ( ) {
985
+ if let Some ( event) = event {
986
+ // Parent exists, failure should be propagated to the parent.
987
+ parent. send_supervision_event_or_crash ( event) ;
988
+ }
989
+ // TODO: we should get rid of this signal, and use *only* supervision events for
990
+ // the purpose of conveying lifecycle changes
974
991
if let Err ( err) = parent. signal ( Signal :: ChildStopped ( self . cell . pid ( ) ) ) {
975
992
tracing:: error!(
976
993
"{}: failed to send stop message to parent pid {}: {:?}" ,
@@ -979,26 +996,14 @@ impl<A: Actor> Instance<A> {
979
996
err
980
997
) ;
981
998
}
982
- if actor_status. is_failed ( ) {
983
- // Parent exists, failure should be propagated to the parent.
984
- parent. send_supervision_event_or_crash ( ActorSupervisionEvent {
985
- actor_id : self . cell . actor_id ( ) . clone ( ) ,
986
- actor_status : actor_status. clone ( ) ,
987
- message_headers : None ,
988
- } ) ;
989
- }
990
999
} else {
991
1000
// Failure happened to the root actor or orphaned child actors.
992
1001
// In either case, the failure should be propagated to proc.
993
1002
//
994
1003
// Note that orphaned actor is unexpected and would only happen if
995
1004
// there is a bug.
996
- if actor_status. is_failed ( ) {
997
- self . proc . handle_supervision_event ( ActorSupervisionEvent {
998
- actor_id : self . cell . actor_id ( ) . clone ( ) ,
999
- actor_status : actor_status. clone ( ) ,
1000
- message_headers : None ,
1001
- } )
1005
+ if let Some ( event) = event {
1006
+ self . proc . handle_supervision_event ( event) ;
1002
1007
}
1003
1008
}
1004
1009
self . change_status ( actor_status) ;
@@ -1103,7 +1108,7 @@ impl<A: Actor> Instance<A> {
1103
1108
let work = work. expect( "inconsistent work queue state" ) ;
1104
1109
if let Err ( err) = work. handle( actor, self ) . await {
1105
1110
for supervision_event in supervision_event_receiver. drain( ) {
1106
- self . handle_supervision_event( actor, supervision_event) . await ;
1111
+ self . handle_supervision_event( actor, supervision_event) . await ? ;
1107
1112
}
1108
1113
return Err ( ActorError :: new( self . self_id( ) . clone( ) , ActorErrorKind :: Processing ( err) ) ) ;
1109
1114
}
@@ -1122,7 +1127,7 @@ impl<A: Actor> Instance<A> {
1122
1127
}
1123
1128
}
1124
1129
Ok ( supervision_event) = supervision_event_receiver. recv( ) => {
1125
- self . handle_supervision_event( actor, supervision_event) . await ;
1130
+ self . handle_supervision_event( actor, supervision_event) . await ? ;
1126
1131
}
1127
1132
}
1128
1133
self . cell
@@ -1154,24 +1159,41 @@ impl<A: Actor> Instance<A> {
1154
1159
& self ,
1155
1160
actor : & mut A ,
1156
1161
supervision_event : ActorSupervisionEvent ,
1157
- ) {
1162
+ ) -> Result < ( ) , ActorError > {
1158
1163
// Handle the supervision event with the current actor.
1159
- if let Ok ( false ) = actor
1164
+ match actor
1160
1165
. handle_supervision_event ( self , & supervision_event)
1161
1166
. await
1162
1167
{
1163
- // The supervision event wasn't handled by this actor, try to bubble it up.
1164
- let result = self . cell . get_parent_cell ( ) ;
1165
- if let Some ( parent) = result {
1166
- parent. send_supervision_event_or_crash ( supervision_event) ;
1167
- } else {
1168
- // Reaching here means the actor is either a root actor, or an orphaned
1169
- // child actor (i.e. the parent actor was dropped unexpectedly). In either
1170
- // case, the supervision event should be sent to proc.
1171
- //
1172
- // Note that orphaned actor is unexpected and would only happen if there
1173
- // is a bug.
1174
- self . proc . handle_supervision_event ( supervision_event) ;
1168
+ Ok ( true ) => {
1169
+ // The supervision event was handled by this actor, nothing more to do.
1170
+ Ok ( ( ) )
1171
+ }
1172
+ Ok ( false ) => {
1173
+ // The supervision event wasn't handled by this actor, chain it and bubble it up.
1174
+ let supervision_event = ActorSupervisionEvent {
1175
+ actor_id : self . self_id ( ) . clone ( ) ,
1176
+ actor_status : ActorStatus :: Failed (
1177
+ "did not handle supervision event" . to_string ( ) ,
1178
+ ) ,
1179
+ message_headers : None ,
1180
+ caused_by : Some ( Box :: new ( supervision_event) ) ,
1181
+ } ;
1182
+ Err ( supervision_event. into ( ) )
1183
+ }
1184
+ Err ( err) => {
1185
+ // The actor failed to handle the supervision event, it should die.
1186
+ // Create a new supervision event for this failure and propagate it.
1187
+ let supervision_event = ActorSupervisionEvent {
1188
+ actor_id : self . self_id ( ) . clone ( ) ,
1189
+ actor_status : ActorStatus :: Failed ( format ! (
1190
+ "failed to handle supervision event: {}" ,
1191
+ err
1192
+ ) ) ,
1193
+ message_headers : None ,
1194
+ caused_by : Some ( Box :: new ( supervision_event) ) ,
1195
+ } ;
1196
+ Err ( supervision_event. into ( ) )
1175
1197
}
1176
1198
}
1177
1199
}
@@ -2174,12 +2196,12 @@ mod tests {
2174
2196
2175
2197
// TODO: should we provide finer-grained stop reasons, e.g., to indicate it was
2176
2198
// stopped by a parent failure?
2177
- assert_matches ! ( root_2_1 . await , ActorStatus :: Stopped ) ;
2178
-
2179
- for actor in [ root_1 , root ] {
2180
- // The other actors were unaffected.
2181
- assert_matches ! ( * actor . status ( ) . borrow ( ) , ActorStatus :: Idle ) ;
2182
- }
2199
+ assert_eq ! (
2200
+ root . await ,
2201
+ ActorStatus :: Failed ( "did not handle supervision event" . to_string ( ) )
2202
+ ) ;
2203
+ assert_eq ! ( root_2_1 . await , ActorStatus :: Stopped ) ;
2204
+ assert_eq ! ( root_1 . await , ActorStatus :: Stopped ) ;
2183
2205
}
2184
2206
2185
2207
#[ tokio:: test]
@@ -2602,8 +2624,111 @@ mod tests {
2602
2624
assert ! ( !root_2_1_state. load( Ordering :: SeqCst ) ) ;
2603
2625
assert_eq ! (
2604
2626
reported_event. event( ) . map( |e| e. actor_id. clone( ) ) ,
2605
- Some ( root_2_1. actor_id( ) . clone( ) )
2627
+ Some ( root. actor_id( ) . clone( ) )
2628
+ ) ;
2629
+ }
2630
+
2631
+ #[ tokio:: test]
2632
+ async fn test_supervision_event_handler_propagates ( ) {
2633
+ #[ derive( Debug ) ]
2634
+ struct FailingSupervisionActor ;
2635
+
2636
+ #[ async_trait]
2637
+ impl Actor for FailingSupervisionActor {
2638
+ type Params = ( ) ;
2639
+
2640
+ async fn new ( _: ( ) ) -> Result < Self , anyhow:: Error > {
2641
+ Ok ( Self )
2642
+ }
2643
+
2644
+ async fn handle_supervision_event (
2645
+ & mut self ,
2646
+ _this : & Instance < Self > ,
2647
+ _event : & ActorSupervisionEvent ,
2648
+ ) -> Result < bool , anyhow:: Error > {
2649
+ anyhow:: bail!( "failed to handle supervision event!" )
2650
+ }
2651
+ }
2652
+
2653
+ #[ async_trait]
2654
+ impl Handler < String > for FailingSupervisionActor {
2655
+ async fn handle (
2656
+ & mut self ,
2657
+ _cx : & crate :: Context < Self > ,
2658
+ message : String ,
2659
+ ) -> anyhow:: Result < ( ) > {
2660
+ Err ( anyhow:: anyhow!( message) )
2661
+ }
2662
+ }
2663
+
2664
+ #[ derive( Debug ) ]
2665
+ struct ParentActor ( tokio:: sync:: mpsc:: UnboundedSender < ActorSupervisionEvent > ) ;
2666
+
2667
+ #[ async_trait]
2668
+ impl Actor for ParentActor {
2669
+ type Params = tokio:: sync:: mpsc:: UnboundedSender < ActorSupervisionEvent > ;
2670
+
2671
+ async fn new (
2672
+ supervision_events : tokio:: sync:: mpsc:: UnboundedSender < ActorSupervisionEvent > ,
2673
+ ) -> Result < Self , anyhow:: Error > {
2674
+ Ok ( Self ( supervision_events) )
2675
+ }
2676
+
2677
+ async fn handle_supervision_event (
2678
+ & mut self ,
2679
+ _this : & Instance < Self > ,
2680
+ event : & ActorSupervisionEvent ,
2681
+ ) -> Result < bool , anyhow:: Error > {
2682
+ self . 0 . send ( event. clone ( ) ) . unwrap ( ) ;
2683
+ Ok ( true )
2684
+ }
2685
+ }
2686
+
2687
+ let proc = Proc :: local ( ) ;
2688
+
2689
+ let ( event_tx, mut event_rx) = tokio:: sync:: mpsc:: unbounded_channel ( ) ;
2690
+
2691
+ let parent = proc. spawn :: < ParentActor > ( "parent" , event_tx) . await . unwrap ( ) ;
2692
+ let child = proc
2693
+ . spawn_child :: < FailingSupervisionActor > ( parent. cell ( ) . clone ( ) , ( ) )
2694
+ . await
2695
+ . unwrap ( ) ;
2696
+ let grandchild = proc
2697
+ . spawn_child :: < FailingSupervisionActor > ( child. cell ( ) . clone ( ) , ( ) )
2698
+ . await
2699
+ . unwrap ( ) ;
2700
+
2701
+ let child_actor_id = child. actor_id ( ) . clone ( ) ;
2702
+ let grandchild_actor_id = grandchild. actor_id ( ) . clone ( ) ;
2703
+
2704
+ // Grandchild fails, triggering failure up the tree, finally receiving
2705
+ // the event at the root.
2706
+ grandchild. send ( "trigger failure" . to_string ( ) ) . unwrap ( ) ;
2707
+
2708
+ assert ! ( grandchild. await . is_failed( ) ) ;
2709
+ assert ! ( child. await . is_failed( ) ) ;
2710
+
2711
+ assert_eq ! (
2712
+ event_rx. recv( ) . await . unwrap( ) ,
2713
+ ActorSupervisionEvent {
2714
+ actor_id: child_actor_id,
2715
+ actor_status: ActorStatus :: Failed (
2716
+ "failed to handle supervision event: failed to handle supervision event!"
2717
+ . to_string( )
2718
+ ) ,
2719
+ message_headers: None ,
2720
+ caused_by: Some ( Box :: new( ActorSupervisionEvent {
2721
+ actor_id: grandchild_actor_id,
2722
+ actor_status: ActorStatus :: Failed (
2723
+ "serving local[0].parent[2]: processing error: trigger failure" . to_string( )
2724
+ ) ,
2725
+ message_headers: None ,
2726
+ caused_by: None ,
2727
+ } ) ) ,
2728
+ }
2606
2729
) ;
2730
+
2731
+ assert ! ( event_rx. try_recv( ) . is_err( ) ) ;
2607
2732
}
2608
2733
2609
2734
#[ tokio:: test]
@@ -2615,7 +2740,7 @@ mod tests {
2615
2740
impl Actor for TestActor {
2616
2741
type Params = ( ) ;
2617
2742
2618
- async fn new ( _param : ( ) ) -> Result < Self , anyhow:: Error > {
2743
+ async fn new ( _params : ( ) ) -> Result < Self , anyhow:: Error > {
2619
2744
Ok ( Self )
2620
2745
}
2621
2746
}
0 commit comments