Classic Actor | Stopping actor

流程

    Stop 一个actor会有有两个步骤,首先actor会暂停其邮箱处理和发送stop command给所有children actors, 这一步骤会在stop children actors阶段持续,直到stop最后一个children actor才会进入下一个步骤,stop自己本身(调用postStop钩子函数,倾销mailbox,通知DeathWatch和supervisor)。 这两个步骤确保actor系统子树以有序的方式销毁,将停止(销毁)命令传播给叶子,并将它们的确认传回supervisor。如果其中一个actor没有响应(即处理消息的时间延长,因此没有收到停止命令),整个进程将被卡住。当完成stop 一个 actor后,会调用postStop()钩子函数,可以在postStop定义清理资源的动作。
需要注意的是,stop actor实际上是异步执行的,在发出stop actor 命令时actor不会立即被销毁,所以在真正销毁之前会持续处理现有的消息,但mailbox的消息不会被处理 (e. stop may return before the actor is stopped.),mailbox中未消费的消息会默认发送到ActorSystem的deadLetters(可通过定义mailbox的实现改变规则)。[1]

方法

1.通过调用ActorRefFactory的stop方法来停止Actor, 例如使用ActorContext或ActorSystem(ActorContext是继承了ActorRefFactory 和ActorSystem是实现ActorRefFactory),通常ActorContext用来stopactor自己及子actor,而ActorSystem用来stop top-level的actors.

2.通过向actor发送akka.actor.PoisonPill 消息,actor当消费到PoisonPill消息时开始执行stop流程。

3.通过向actor发送akka.actor.Kill消息,与PoisonPill不同的是,Kill actor会抛出ActorKilledException,好处就是触发exception时会去询问它的supervisor如何去处理(恢复,重启,停止)。

4.通过gracefulStop 方法stop actors,适用于设置等待终止时间和通过stop若干个actor的场景

实践

import akka.actor.AbstractActor;
import akka.actor.Props;
import akka.event.Logging;
import akka.event.LoggingAdapter;
import java.util.HashMap;
import java.util.Map;
public class RequestActor5 extends AbstractActor {
    protected final String name;
    protected final LoggingAdapter log = Logging.getLogger(context().system(),this);
    protected final Map<String, Object> map = new HashMap<>();
    public RequestActor5(String name) {
        this.name = name;
    }
    static Props props(String name) {
        return Props.create(RequestActor5.class, name);
    }
    @Override
    public Receive createReceive() {
        return receiveBuilder()
                .matchEquals("done",message -> {
                    getContext().stop(getSelf());
                })
                .match(String.class,message->{
                    log.info("Received Request {}",message);
                    map.put("StringMessage",message);
                })
                .matchAny(o->log.info("Received unknow message {}",o))
                .build();
    }
    @Override
    public void postStop() throws Exception {
        System.out.println("RequestActor5 is done");
    }
}

import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.Kill;
import akka.actor.PoisonPill;
import akka.testkit.TestActorRef;
import org.junit.jupiter.api.Test;
class RequestActor5Test {
    ActorSystem system = ActorSystem.create();
    @Test
    public void test1() {
        TestActorRef<RequestActor5> actorRef = TestActorRef.create(system, RequestActor5.props("request"));
        actorRef.tell(Kill.getInstance(), ActorRef.noSender());
    }
    @Test
    public void test2() {
        TestActorRef<RequestActor5> actorRef = TestActorRef.create(system, RequestActor5.props("request"));
        actorRef.tell(PoisonPill.getInstance(), ActorRef.noSender());
    }
    @Test
    public void test3() {
        TestActorRef<RequestActor5> actorRef = TestActorRef.create(system, RequestActor5.props("request"));
        actorRef.tell("done", ActorRef.noSender());
    }
    @Test
    public void test4() {
        TestActorRef<RequestActor5> actorRef = TestActorRef.create(system, RequestActor5.props("request"));
        actorRef.tell("message", ActorRef.noSender());
        system.stop(actorRef);
    }
}

posted @ 2020-11-13 21:15  听说这是最长的名字了  阅读(122)  评论(0编辑  收藏  举报