监督策略
Akka框架给予了我们足够的控制权。在Akka框架内,父Acotr可以对子Actor进行监督,监控Actor的行为是否有异常,监督策略可以分为两种:一种是OneForOneStrategy策略的监督(只会对出问题的子Actor进行处理),另外一种是AllForOneStrategy(会对出问题的子Acotr及它所有的兄弟都进行处理,适合各个Actor联系非常紧密的场景)策略的监督。
自定义的监督策略(supervisorStrategy)
定义一个OneForOneStrategy策略的监督。在这个监督策略中,运行Actor遇到错误后,在1分钟内进行3次重试,如果超过这个频率,就直接杀死Actor。当遇到ArithmeticException异常时(比如除以0的错误),继续指定这个Actor,不做任何处理;当遇到空指针时,进行重启。如果遇到IlleganArgumentException,直接停止Acotr
public class Supervisor extends UntypedAbstractActor {
private static SupervisorStrategy strategy=
new OneForOneStrategy(3, Duration.create(1, TimeUnit.MINUTES), //一分钟重试3次
new Function<Throwable, SupervisorStrategy.Directive>() {
@Override
public SupervisorStrategy.Directive apply(Throwable param) throws Exception {
if(param instanceof ArithmeticException){
System.out.println("meet ArithmeticException,just resume");
return SupervisorStrategy.resume();
}else if(param instanceof NullPointerException){
System.out.println("meet NullPointerException,restart");
return SupervisorStrategy.restart();
}else if(param instanceof IllegalArgumentException){
return SupervisorStrategy.stop();
}else {
return SupervisorStrategy.escalate();
}
}
});
public static SupervisorStrategy getStrategy() {
return strategy;
}
@Override
public void onReceive(Object message) throws Throwable {
if(message instanceof Props){
getContext().actorOf((Props) message,"restartActor");
}else {
unhandled(message);
}
}
}
public class RestartActor extends UntypedAbstractActor {
public enum Msg{
DONE,RESTART;
}
@Override
public void preStart() throws Exception {
System.out.println("preStart hashcode:"+this.hashCode());
}
@Override
public void postStop() throws Exception {
System.out.println("postStop hashcode:"+this.hashCode());
}
@Override
public void postRestart(Throwable reason) throws Exception {
super.postRestart(reason);
System.out.println("postRestart hashcode:"+this.hashCode());
}
@Override
public void preRestart(Throwable reason, Optional<Object> message) throws Exception {
System.out.println("preSRestart hashcode:"+this.hashCode());
}
@Override
public void onReceive(Object message) throws Throwable {
if(message==Msg.DONE){
getContext().stop(getSelf());
}else if(message==Msg.RESTART){
System.out.println("--------");
double a=0/0;//resume
}
unhandled(message);
}
public static void main(String[] args) {
ActorSystem system = ActorSystem.create("lifeStyle");
ActorRef a=system.actorOf(Props.create(Supervisor.class),"supervisor");
a.tell(Props.create(RestartActor.class),ActorRef.noSender());
ActorSelection sel=system.actorSelection("akka://lifeStyle/user/supervisor/restartActor");
for (int i = 0; i < 100; i++) {
sel.tell(Msg.RESTART,ActorRef.noSender());
}
}
}
可以看到preStart表示RestartActor正在初始化,它的hashcode是1276294244,当遇到空指针异常时,根据自定义的策略,导致它重启,在重启前调用了preRestart方法,此时hashcode还是1276294244,生成了新的实例之后,preStart的hashcode变成了99731995,并且返回postRestart方法的hashcode也是99731995,原有的实例因为重启而被挥手。这说明同一个Actor在系统工作始终未必能保持同一个实例。
选择Actor
在一个ActorSystem中,可能存在大量的Actor。如何才能有效地对大量Actor进行批量的管理和通信呢?Akka为我们提供了一个ActorSelection类,用来进行批量消息发送。
for(int i=0;i<WORDER_COUNT;i++){
workers.add(system.actorOf(Props.create(MyWorker.class,i),"worker_"+i));
}
ActorSelection selection=getContext().actorSelection("/user/worker_*");
selection.tell(5,getSelf());
上述代码批量生成了大量Actor,我们要给这些worker发送消息,通过actorSelection()方法提供的选择通配符,可以得到代表所有满足条件的ActorSelection。