Skip to content

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

Description

@markhildreth

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();
}

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions