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

Actors do not stop after addresses dropped due to run_interval #285

Open
markhildreth opened this issue Sep 18, 2019 · 2 comments
Open

Actors do not stop after addresses dropped due to run_interval #285

markhildreth opened this issue Sep 18, 2019 · 2 comments

Comments

@markhildreth
Copy link

I'm using Actix 0.7.9. I'm reading this documentation, which says the following:

The Actor's execution state changes to the stopping state in the following situations:

  • Context::stop is called by the actor itself
  • all addresses to the actor get dropped. i.e. no other actor references it.
  • no event objects are registered in the context.

I was slightly confused then when an actor was not being stopped even though the situation described by the second bullet occurred ("all addresses to the actor get dropped"). Through testing, I realized that the reason was because the actor had a run_interval function. If I removed that interval function, it would stop as expected.

I'm not sure if using run_interval in this way is what is meant in the third bullet ("no event objects are registered in the context." However, even in that case the wording is such that I would assume that the actor stops if any of the three situations occur, regardless of the others.

I'm not sure if this is a situation where the behavior is as-expected, and the documentation needs to be touched up, or if there is a bug.

Example Code

Based on the documentation, I would expect that this code stop the child actor almost immediately after stopping the parent actor. Instead, the child actor lives forever.

use actix::prelude::*;
use std::time::Duration;

struct Parent {
    children_addrs: Vec<Addr<Child>>
}

impl Actor for Parent {
    type Context = Context<Self>;

    fn started(&mut self, ctx: &mut Self::Context) {
        println!("Parent starting");

        let child = Child { parent_addr: ctx.address() };
        self.children_addrs.push(child.start());
        ctx.run_later(Duration::from_millis(500), |actor, ctx| {
            ctx.stop();
        }); 
    }   

    fn stopped(&mut self, _ctx: &mut Self::Context) {
        println!("Parent Stopped");
    }   
}

struct Child {
    parent_addr: Addr<Parent>
}

impl Actor for Child {
    type Context = Context<Self>;

    fn started(&mut self, ctx: &mut Self::Context) {
        println!("Child started");
        ctx.run_interval(Duration::from_secs(2), |actor, ctx| {
            println!("Running interval for child");
        }); 
    }   

    fn stopped(&mut self, _ctx: &mut Self::Context) {
        println!("Child Stopped");
    }   
}

fn main() {
    let system = actix::System::new("test");

    let parent = Parent {
        children_addrs: Vec::new()
    };  
    parent.start();
    system.run();
}
@markhildreth markhildreth changed the title Actors do not stop after addresses dropped due to interval Actors do not stop after addresses dropped due to run_interval Sep 18, 2019
@hoodie
Copy link
Contributor

hoodie commented May 3, 2020

just ran into the same question. is there any best practice here? how do I stop an interval?


UPDATE: oops my bad 😄 of course the interval stops when its context is stopped, I had a bug and didn't stop my actor correctly under all circumstances.

@jracollins
Copy link

@markhildreth - Did you find any solution to this?

I have found any of the interval/run_later commands have this effect (eg, run_later, notify_later) seem to cause it.

Not sure how to run things like a heartbeat for a websocket actor an if an interval or calling these other methods once prevents it from ever being stopped. (This problem is made worse if it is a supervised actor, and all addresses being dropped is the only real way to stop the actor, as a ctx.stop() will just cause it to be restarted).

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