Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The IActorRef of a child dies or restarts could not be retrieve by mailbox.Sender() in parent #6272

Open
ingted opened this issue Nov 28, 2022 · 3 comments
Milestone

Comments

@ingted
Copy link

ingted commented Nov 28, 2022

========================================
Version of Akka.NET? 1.5.0-Alpha
Which Akka.NET Modules? Akka or Akka.FSharp

The IActorRef of a child dies or restarts could not be retrieve by mailbox.Sender() in parent

========================================
Reproduce

Example Code File Location

#if INTERACTIVE
#r @"nuget: Akka"
#r @"nuget: Akka.FSharp"
#endif


open System
open Akka.Actor
open Akka.Configuration
open Akka.FSharp

type CustomException() =
    inherit Exception()

type Message =
    | Echo of string
    | Crash

let system = System.create "system" (Configuration.defaultConfig())
    // create parent actor to watch over jobs delegated to it's child
let parent = 
    spawnOpt system "parent" 
        <| fun parentMailbox ->
            // define child actor
            let child = 
                    spawn parentMailbox "child" <| fun childMailbox ->
                        childMailbox.Defer (fun () -> printfn "Child stopping")
                        printfn "Child started"
                        let rec childLoop() = 
                            actor {
                                let! msg = childMailbox.Receive()
                                match msg with
                                | Echo info -> 
                                    // respond to original sender
                                    let response = "Child " + (childMailbox.Self.Path.ToStringWithAddress()) + " received: "  + info
                                    childMailbox.Sender() <! response
                                | Crash -> 
                                    // log crash request and crash
                                    //printfn "Child %A received crash order" (childMailbox.Self.Path)
                                    raise (CustomException())
                                return! childLoop()
                            }
                        childLoop()
            // define parent behavior
            let rec parentLoop() =
                actor {
                    let! (msg: Message) = parentMailbox.Receive()
                    child.Forward(msg)  // forward all messages through

                    //###########################################
                    //###### Notice this sender()

                    let sender = parentMailbox.Sender()
                    if sender <> null then
                        printfn "sender: %A" sender

                    //###########################################
                    return! parentLoop()
                }
            parentLoop()
        // define supervision strategy
        <| [ SpawnOption.SupervisorStrategy (
                // restart on Custom Exception, default behavior on all other exception types
                Strategy.OneForOne(fun e ->
                match e with
                | :? CustomException -> Directive.Restart 
                | _ -> SupervisorStrategy.DefaultDecider.Decide(e)
                //Directive.Restart
                )
        )  ]


parent <! Crash

=> See "Notice this sender()"

Expected behavior

The parentMailbox.Sender() should give us the IActorRef of child

Actual behavior

The parentMailbox.Sender() is null

Environment

Windows Server 2019 + .NET 7.0

@ingted
Copy link
Author

ingted commented Nov 28, 2022

According to fault-tolerance

If the strategy is declared inside the supervising actor (as opposed to within a companion object) its decider has access to all internal state of the actor in a thread-safe fashion, including obtaining a reference to the currently failed child (available as the Sender of the failure message).

@ingted
Copy link
Author

ingted commented Nov 28, 2022

Workaround:

derive the SupervisorStrategy class and put the error handler inside it...

type SS () =
    inherit SupervisorStrategy ()   
    override u.Decider :IDecider = 
        //Unchecked.defaultof<IDecider>
        SupervisorStrategy.DefaultDecider
    override u.Handle(child:IActorRef, exn:Exception) =
        //Unchecked.defaultof<Directive>
        Directive.Restart
    override u.ProcessFailure(
        context:IActorContext, 
        restart:bool, 
        child:IActorRef, 
        cause:Exception, 
        stats:ChildRestartStats, 
        children:IReadOnlyCollection<ChildRestartStats>) =
            printfn "====> %A" child
    override u.HandleChildTerminated(
        actorContext:IActorContext,  
        child:IActorRef, 
        children:IEnumerable<IInternalActorRef>) = 
            printfn "====> %A" child
    override u.ToSurrogate(system:ActorSystem) =
        Unchecked.defaultof<ISurrogate>
<| [ SpawnOption.SupervisorStrategy (SS ()) ]

@ingted
Copy link
Author

ingted commented Nov 28, 2022

It seems like we can override the method to send the IActorRef back to parent's mailbox...
But this is not convinient like the Sender() method... (illustrated in the document)

@Aaronontheweb Aaronontheweb added this to the 1.5.0 milestone Nov 28, 2022
@Aaronontheweb Aaronontheweb modified the milestones: 1.5.0, 1.5.1 Mar 2, 2023
@Aaronontheweb Aaronontheweb modified the milestones: 1.5.1, 1.5.2 Mar 15, 2023
@Aaronontheweb Aaronontheweb modified the milestones: 1.5.2, 1.5.3 Apr 6, 2023
@Aaronontheweb Aaronontheweb modified the milestones: 1.5.3, 1.5.4, 1.5.5 Apr 20, 2023
@Aaronontheweb Aaronontheweb modified the milestones: 1.5.5, 1.5.6, 1.5.7 May 4, 2023
@Aaronontheweb Aaronontheweb modified the milestones: 1.5.7, 1.5.8 May 17, 2023
@Aaronontheweb Aaronontheweb modified the milestones: 1.5.8, 1.5.9 Jun 15, 2023
@Aaronontheweb Aaronontheweb modified the milestones: 1.5.9, 1.5.11, 1.5.12 Jul 25, 2023
@Aaronontheweb Aaronontheweb modified the milestones: 1.5.12, 1.5.13 Aug 2, 2023
@Aaronontheweb Aaronontheweb removed this from the 1.5.13 milestone Sep 20, 2023
@Aaronontheweb Aaronontheweb modified the milestones: 1.5.20, 1.5.21 Apr 29, 2024
@Aaronontheweb Aaronontheweb modified the milestones: 1.5.21, 1.5.22, 1.5.23 May 28, 2024
@Aaronontheweb Aaronontheweb modified the milestones: 1.5.23, 1.5.24, 1.5.25 Jun 6, 2024
@Aaronontheweb Aaronontheweb modified the milestones: 1.5.25, 1.5.26 Jun 14, 2024
@Aaronontheweb Aaronontheweb modified the milestones: 1.5.26, 1.5.27 Jun 27, 2024
@Aaronontheweb Aaronontheweb modified the milestones: 1.5.27, 1.5.28 Jul 25, 2024
@Aaronontheweb Aaronontheweb modified the milestones: 1.5.28, 1.5.29 Sep 4, 2024
@Aaronontheweb Aaronontheweb modified the milestones: 1.5.29, 1.5.30, 1.5.31 Oct 1, 2024
@Aaronontheweb Aaronontheweb modified the milestones: 1.5.31, 1.5.32 Nov 14, 2024
@Aaronontheweb Aaronontheweb modified the milestones: 1.5.32, 1.5.33 Dec 4, 2024
@Aaronontheweb Aaronontheweb modified the milestones: 1.5.33, 1.5.34 Dec 24, 2024
@Aaronontheweb Aaronontheweb modified the milestones: 1.5.34, 1.5.35 Jan 7, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants