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

terminate actor with no more messages guarantee #104

Open
aav opened this issue Jun 5, 2020 · 5 comments
Open

terminate actor with no more messages guarantee #104

aav opened this issue Jun 5, 2020 · 5 comments

Comments

@aav
Copy link

aav commented Jun 5, 2020

Currently, there is no way to terminate the actor from recv callback in a way, that no messages will arrive (recv will not be called) after termination. Clearly ctx.stop(ctx.myself()); does not satisfy this criteria.

Here is the typical use case:

impl Actor for MyActor {
    type Msg = MyEvent;

    fn post_start(&mut self, ctx: &Context<Self::Msg>) {
        // do request wait for MyEvent::Response
        issue_request_to_someont(ctx.myself());

        // or MyEvent::Timeout 
        ctx.schedule_once(ctx.myself(), Duration::from_sec(1), MyEvent::Timeout)
    }
    
    fn recv(&mut self, ctx: &Context<Self::Msg>, msg: Self::Msg, _sender: Sender) {
        match msg {
            MyEvent::Response(_) => {
                // handle response
            },

            MyEvent::Timeout => {
                // handle timeout
            }
        }
        
        // missing :(
        ctx.terminate();
   }
}

In Erlang, I would simply stop receiving messages and leave the process function. Since here we are based on callback, I believe that such a function is really important.

@leenozara
Copy link
Contributor

@aav can you confirm that this is the case? ctx.stop is a system message. Any system messages in an actor’s mailbox will be handled before user messages. A check for system messages is done after every user message is handled.

@aav
Copy link
Author

aav commented Jun 16, 2020

@leenozara
I will double-check (almost sure, I observed this behavior) and create an example. In case I will not be able to make it (my error) - I will close the issue.

@aav
Copy link
Author

aav commented Jun 20, 2020

Here is the code example:

use std::time::Duration;
use riker::actors::*;

#[derive(Default)]
struct MyActor;

impl Actor for MyActor {
    type Msg = i32;

    fn recv(&mut self, ctx: &Context<Self::Msg>, msg: Self::Msg, _sender: Sender) {
        println!("message: {:?}", msg);

        if msg == 5 {
            println!("stop");
            ctx.stop(ctx.myself());
        }
    }
}

fn main() {
    let sys = ActorSystem::new().unwrap();
    
    let actor = sys.actor_of::<MyActor>("actor").unwrap();

    for n in 0..10 {
        actor.tell(n, None);
    }
    
    std::thread::sleep(Duration::from_millis(5000));
}

and here is the output:

2020-06-20 15:09:15+00:00 DEBG [riker::system] Starting actor system: System[riker]
2020-06-20 15:09:15+00:00 DEBG [riker::system] Actor system [bfd38e4c-1949-4a8a-b814-e9bd83397ff4] [riker] started
message: 0
message: 1
message: 2
message: 3
message: 4
message: 5
stop
message: 6
message: 7
message: 8
message: 9

I would expect that after ctx.stop(ctx.myself()) recv callback will never be called again.

@leenozara
Copy link
Contributor

Thanks for checking and confirming that. I’ll take a look to see why this is the case.

@milgner
Copy link

milgner commented Nov 25, 2021

@aav did you happen to find a solution to this? I'm currently struggling with a similar situation where even though we're calling context.stop(actor_ref) the post_stop method isn't invoked and the actor is kept alive.

Update: for some reason everything works as expected when using tmp_actor_of but not with regular child actors...

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

No branches or pull requests

3 participants