Actor生命周期

akka版本2.6.9
版权声明:本文为博主原创文章,未经博主允许不得转载。

 要使用Akka Actor类型,您必须在项目中添加以下依赖项:

<properties>
  <akka.version>2.6.10</akka.version>
  <scala.binary.version>2.13</scala.binary.version>
</properties>
<dependency>
  <groupId>com.typesafe.akka</groupId>
  <artifactId>akka-actor-typed_${scala.binary.version}</artifactId>
  <version>${akka.version}</version>
</dependency>

介绍
 Actor是必须显式启动和停止的有状态资源。
 重要的是要注意,当不再引用Actor时,Actor不会自动停止,创建的每个Actor也必须显式地销毁。惟一的简化是,停止父Actor还将递归地停止该父Actor创建的所有子Actor。当角色系统关闭时,所有的角色也会自动停止。

请注意
 ActorSystem是重量级结构,它将分配线程,因此为每个逻辑应用程序创建一个线程。通常每个JVM进程有一个actor系统。

创建角色
 一个actor可以创建或衍生任意数量的子actor,而子actor又可以衍生自己的子actor,从而形成一个actor层次结构。ActorSystem托管层次结构,并且只能有一个根actor,即位于ActorSystem层次结构顶端的actor。子角色的生命周期与父角色相关联——子角色可以停止自己或在任何时候被停止,但它永远无法活过父角色。

ActorContext
 ActorContext可以被多种目的访问,例如:

  • 创建子的actor和监督
  • 监听其他actor以接收一个终止的(其他actor)事件,如果被观察的actor永久停止
  • 日志记录
  • 创建消息适配器
  • 与另一个Actor的请求-响应交互(ask)
  • 对self ActorRef的访问

 如果一个行为需要使用ActorContext,例如衍生子actor,或者使用context.getSelf(),它可以通过用Behaviors.setup包装构造来获得:

public class HelloWorldMain extends AbstractBehavior<HelloWorldMain.SayHello> {
 public static Behavior<SayHello> create() {
   return Behaviors.setup(HelloWorldMain::new);
 }

 private final ActorRef<HelloWorld.Greet> greeter;

 private HelloWorldMain(ActorContext<SayHello> context) {
   super(context);
   greeter = context.spawn(HelloWorld.create(), "greeter");
 }
}

ActorContext线程安全
 ActorContext中的许多方法都不是线程安全的

  • 不能被来自java.util.concurrent的线程访问。CompletionStage回调
  • 不能在多个actor实例之间共享
  • 必须只在普通actor线程中使用消息处理

守护actor
 顶级Actor,也称为用户监护actor,是与ActorSystem一起创建的。发送到actor系统的消息被定向到根actor。根actor是由用来创建ActorSystem的行为定义的,在下面的例子中命名为HelloWorldMain:

final ActorSystem<HelloWorldMain.SayHello> system =
    ActorSystem.create(HelloWorldMain.create(), "hello");

system.tell(new HelloWorldMain.SayHello("World"));
system.tell(new HelloWorldMain.SayHello("Akka"));

 对于非常简单的应用程序,guardian可能包含实际的应用程序逻辑和处理消息。一旦应用程序处理了不止一个问题,监护人就应该引导应用程序,将各种子系统作为子系统生成,并监视它们的生命周期。
 当守护actor停止时,将停止actor系统。
 当ActorSystem。协调关闭流程将以特定的顺序停止actor和服务。
生成子actor
 子actor是通过ActorContext的衍生来创建和启动的。在下面的示例中,当根actor启动时,它会生成一个由HelloWorld行为描述的子actor。此外,当根actor接收到SayHello消息时,它会创建一个由行为HelloWorldBot定义的子actor:

public class HelloWorldMain extends AbstractBehavior<HelloWorldMain.SayHello> {

  public static class SayHello {
    public final String name;

    public SayHello(String name) {
      this.name = name;
    }
  }

  public static Behavior<SayHello> create() {
    return Behaviors.setup(HelloWorldMain::new);
  }

  private final ActorRef<HelloWorld.Greet> greeter;

  private HelloWorldMain(ActorContext<SayHello> context) {
    super(context);
    greeter = context.spawn(HelloWorld.create(), "greeter");
  }

  @Override
  public Receive<SayHello> createReceive() {
    return newReceiveBuilder().onMessage(SayHello.class, this::onStart).build();
  }

  private Behavior<SayHello> onStart(SayHello command) {
    ActorRef<HelloWorld.Greeted> replyTo =
        getContext().spawn(HelloWorldBot.create(3), command.name);
    greeter.tell(new HelloWorld.Greet(command.name, replyTo));
    return this;
  }
}

 要在生成actor时指定dispatcher,请使用DispatcherSelector。如果未指定,则参与者将使用默认分派器,有关详细信息,请参阅default分派器。

public class HelloWorldMain extends AbstractBehavior<HelloWorldMain.SayHello> {

  // Start message...

  public static Behavior<SayHello> create() {
    return Behaviors.setup(HelloWorldMain::new);
  }

  private final ActorRef<HelloWorld.Greet> greeter;

  private HelloWorldMain(ActorContext<SayHello> context) {
    super(context);

    final String dispatcherPath = "akka.actor.default-blocking-io-dispatcher";
    Props greeterProps = DispatcherSelector.fromConfig(dispatcherPath);
    greeter = getContext().spawn(HelloWorld.create(), "greeter", greeterProps);
  }

  // createReceive ...
}

 请参考actor了解上述示例的大致内容。
SpawnProtocol
 监护actor应该负责任务的初始化,并创建应用程序的初始actor,但有时您可能希望从监护参与者的外部派生新的参与者。例如,为每个HTTP请求创建一个actor。
 这在您的行为中并不难实现,但是由于这是一种常见的模式,因此有一个预定义的消息协议和行为实现。它可以作为行为人系统的监护行为人,也可以与行为相结合。设置以启动一些初始任务或actor。然后可以通过告诉或询问SpawnProtocol从外部启动子actor。衍生到系统的actor引用。使用ask类似于如何ActorSystem。actorOf可以在经典的actor中使用,区别在于返回ActorRef的CompletionStage。
监护人行为可以定义为:

import akka.actor.typed.Behavior;
import akka.actor.typed.SpawnProtocol;
import akka.actor.typed.javadsl.Behaviors;

public abstract class HelloWorldMain {
  private HelloWorldMain() {}

  public static Behavior<SpawnProtocol.Command> create() {
    return Behaviors.setup(
        context -> {
          // Start initial tasks
          // context.spawn(...)

          return SpawnProtocol.create();
        });
  }
}

 和ActorSystem 可以创建与main为和要求衍生其他actor:

import akka.actor.typed.ActorRef;
import akka.actor.typed.ActorSystem;
import akka.actor.typed.Props;
import akka.actor.typed.javadsl.AskPattern;

final ActorSystem<SpawnProtocol.Command> system =
    ActorSystem.create(HelloWorldMain.create(), "hello");
final Duration timeout = Duration.ofSeconds(3);

CompletionStage<ActorRef<HelloWorld.Greet>> greeter =
    AskPattern.ask(
        system,
        replyTo ->
            new SpawnProtocol.Spawn<>(HelloWorld.create(), "greeter", Props.empty(), replyTo),
        timeout,
        system.scheduler());

Behavior<HelloWorld.Greeted> greetedBehavior =
    Behaviors.receive(
        (context, message) -> {
          context.getLog().info("Greeting for {} from {}", message.whom, message.from);
          return Behaviors.stopped();
        });

CompletionStage<ActorRef<HelloWorld.Greeted>> greetedReplyTo =
    AskPattern.ask(
        system,
        replyTo -> new SpawnProtocol.Spawn<>(greetedBehavior, "", Props.empty(), replyTo),
        timeout,
        system.scheduler());

greeter.whenComplete(
    (greeterRef, exc) -> {
      if (exc == null) {
        greetedReplyTo.whenComplete(
            (greetedReplyToRef, exc2) -> {
              if (exc2 == null) {
                greeterRef.tell(new HelloWorld.Greet("Akka", greetedReplyToRef));
              }
            });
      }
    });

 SpawnProtocol也可以在actor层次结构的其他地方使用。它不必是根守护角色。
 在Actor发现中描述了查找运行Actor的方法。
停止actor
 一个actor可以通过返回行为来停止自己。停止作为下一个行为。
通过使用父actor的ActorContext的stop方法,可以强制子actor在处理完当 前消息后停止。只有童星可以用这种方式停止。
 所有的子actor将在其父actor被停止时停止。
 当一个actor停止时,它会接收到一个PostStop信号,这个信号可以用来清理资源。一个回调函数可以被指定为行为的参数。在优雅停止时处理PostStop信号。这允许在突然停止时应用不同的操作。
 下面是一个例子:

import java.util.concurrent.TimeUnit;

import akka.actor.typed.ActorSystem;
import akka.actor.typed.Behavior;
import akka.actor.typed.PostStop;
import akka.actor.typed.javadsl.AbstractBehavior;
import akka.actor.typed.javadsl.ActorContext;
import akka.actor.typed.javadsl.Behaviors;
import akka.actor.typed.javadsl.Receive;


public class MasterControlProgram extends AbstractBehavior<MasterControlProgram.Command> {

  interface Command {}

  public static final class SpawnJob implements Command {
    public final String name;

    public SpawnJob(String name) {
      this.name = name;
    }
  }

  public enum GracefulShutdown implements Command {
    INSTANCE
  }

  public static Behavior<Command> create() {
    return Behaviors.setup(MasterControlProgram::new);
  }

  public MasterControlProgram(ActorContext<Command> context) {
    super(context);
  }

  @Override
  public Receive<Command> createReceive() {
    return newReceiveBuilder()
        .onMessage(SpawnJob.class, this::onSpawnJob)
        .onMessage(GracefulShutdown.class, message -> onGracefulShutdown())
        .onSignal(PostStop.class, signal -> onPostStop())
        .build();
  }

  private Behavior<Command> onSpawnJob(SpawnJob message) {
    getContext().getSystem().log().info("Spawning job {}!", message.name);
    getContext().spawn(Job.create(message.name), message.name);
    return this;
  }

  private Behavior<Command> onGracefulShutdown() {
    getContext().getSystem().log().info("Initiating graceful shutdown...");

    // perform graceful stop, executing cleanup before final system termination
    // behavior executing cleanup is passed as a parameter to Actor.stopped
    return Behaviors.stopped(() -> getContext().getSystem().log().info("Cleanup!"));
  }

  private Behavior<Command> onPostStop() {
    getContext().getSystem().log().info("Master Control Program stopped");
    return this;
  }
}

public class Job extends AbstractBehavior<Job.Command> {

  interface Command {}

  public static Behavior<Command> create(String name) {
    return Behaviors.setup(context -> new Job(context, name));
  }

  private final String name;

  public Job(ActorContext<Command> context, String name) {
    super(context);
    this.name = name;
  }

  @Override
  public Receive<Job.Command> createReceive() {
    return newReceiveBuilder().onSignal(PostStop.class, postStop -> onPostStop()).build();
  }

  private Behavior<Command> onPostStop() {
    getContext().getSystem().log().info("Worker {} stopped", name);
    return this;
  }
}

final ActorSystem<MasterControlProgram.Command> system =
    ActorSystem.create(MasterControlProgram.create(), "B6700");

system.tell(new MasterControlProgram.SpawnJob("a"));
system.tell(new MasterControlProgram.SpawnJob("b"));

// sleep here to allow time for the new actors to be started
Thread.sleep(100);

system.tell(MasterControlProgram.GracefulShutdown.INSTANCE);

system.getWhenTerminated().toCompletableFuture().get(3, TimeUnit.SECONDS);

 在从PostStop清理资源时,您还应该考虑对PreRestart信号执行相同的操作,该信号是在actor重新启动时发出的。注意,PostStop不是为重新启动而发出的。
监听actor
 为了在另一个actor终止时得到通知(即永久停止,而不是临时失败并重新启动),一个actor可以监视另一个actor。被观察actor的终止(见停止actor)时,将收到终止信号。

public class MasterControlProgram extends AbstractBehavior<MasterControlProgram.Command> {

  interface Command {}

  public static final class SpawnJob implements Command {
    public final String name;

    public SpawnJob(String name) {
      this.name = name;
    }
  }

  public static Behavior<Command> create() {
    return Behaviors.setup(MasterControlProgram::new);
  }

  public MasterControlProgram(ActorContext<Command> context) {
    super(context);
  }

  @Override
  public Receive<Command> createReceive() {
    return newReceiveBuilder()
        .onMessage(SpawnJob.class, this::onSpawnJob)
        .onSignal(Terminated.class, this::onTerminated)
        .build();
  }

  private Behavior<Command> onSpawnJob(SpawnJob message) {
    getContext().getSystem().log().info("Spawning job {}!", message.name);
    ActorRef<Job.Command> job = getContext().spawn(Job.create(message.name), message.name);
    getContext().watch(job);
    return this;
  }

  private Behavior<Command> onTerminated(Terminated terminated) {
    getContext().getSystem().log().info("Job stopped: {}", terminated.getRef().path().name());
    return this;
  }
}

 监视的另一种方法是watchWith,它允许指定自定义消息而不是终止消息。这通常比使用watch和终止信号更可取,因为可以在消息中包含其他信息,以便稍后接收时使用。
 与上面的示例类似,但是在任务完成时使用watchWith并对原始请求者进行应答。

public class MasterControlProgram extends AbstractBehavior<MasterControlProgram.Command> {

  interface Command {}

  public static final class SpawnJob implements Command {
    public final String name;
    public final ActorRef<JobDone> replyToWhenDone;

    public SpawnJob(String name, ActorRef<JobDone> replyToWhenDone) {
      this.name = name;
      this.replyToWhenDone = replyToWhenDone;
    }
  }

  public static final class JobDone {
    public final String name;

    public JobDone(String name) {
      this.name = name;
    }
  }

  private static final class JobTerminated implements Command {
    final String name;
    final ActorRef<JobDone> replyToWhenDone;

    JobTerminated(String name, ActorRef<JobDone> replyToWhenDone) {
      this.name = name;
      this.replyToWhenDone = replyToWhenDone;
    }
  }

  public static Behavior<Command> create() {
    return Behaviors.setup(MasterControlProgram::new);
  }

  public MasterControlProgram(ActorContext<Command> context) {
    super(context);
  }

  @Override
  public Receive<Command> createReceive() {
    return newReceiveBuilder()
        .onMessage(SpawnJob.class, this::onSpawnJob)
        .onMessage(JobTerminated.class, this::onJobTerminated)
        .build();
  }

  private Behavior<Command> onSpawnJob(SpawnJob message) {
    getContext().getSystem().log().info("Spawning job {}!", message.name);
    ActorRef<Job.Command> job = getContext().spawn(Job.create(message.name), message.name);
    getContext().watchWith(job, new JobTerminated(message.name, message.replyToWhenDone));
    return this;
  }

  private Behavior<Command> onJobTerminated(JobTerminated terminated) {
    getContext().getSystem().log().info("Job stopped: {}", terminated.name);
    terminated.replyToWhenDone.tell(new JobDone(terminated.name));
    return this;
  }
}

 请注意replyToWhenDone是如何包含在watchWith消息中,然后在稍后接收终止作业的消息时使用的。
 被观察的actor可以是任何ActorRef,它不必是上面示例中的子actor。
应该注意,终止消息的生成与注册和终止发生的顺序无关。特别是,即使被监视的actor在注册时已经被终止,监视的actor也会收到终止消息。
多次注册并不一定导致产生多条消息,但没有保证只有一个收到这样的消息:如果终止观看actor的生成和消息排队,和另一个注册这个消息被处理之前完成,然后第二个消息将被排队,因为注册的监控已经终止的actor会导致立即终止消息的一代。
 它也可以取消观看另一个actor的动态使用背景。unwatch(目标)。即使终止的消息已经在邮箱中排队,这也可以工作;在调用unwatch后,不会再处理该actor的终止消息。
 当被监视的actor位于已从集群中删除的节点上时,也会发送终止的消息。

你可能感兴趣的:(AKKA,flink,spark)