使用Akka Scheduler安排作业的过程如下(至少从文档中可以看出):
system.scheduler().schedule(
Duration.Zero(),
Duration.create(5, TimeUnit.SECONDS),
workerActor,
new MessageToTheActor(),
system.dispatcher(), ActorRef.noSender());
但是我不明白如何确保下一次运行仅在当前运行完成后才能进行。我一直到处都没有成功:(
答案 0 :(得分:2)
调度程序对于您的用例来说是错误的工具。
另一种选择是Akka Stream的Sink.actorRefWithAck
(下面的代码根据链接的文档中的示例改编,并借用此处定义的实用程序类)。您将需要调整工作角色,以处理一些与流状态有关的消息并以确认消息进行回复。确认消息用作背压信号,并指示参与者已准备好处理下一个MessageToTheActor
消息。工人演员看起来类似于以下内容:
enum Ack {
INSTANCE;
}
static class StreamInitialized {}
static class StreamCompleted {}
static class StreamFailure {
private final Throwable cause;
public StreamFailure(Throwable cause) { this.cause = cause; }
public Throwable getCause() { return cause; }
}
public class MyWorker extends AbstractLoggingActor {
@Override
public Receive createReceive() {
return receiveBuilder()
.match(StreamInitialized.class, init -> {
log().info("Stream initialized");
sender().tell(Ack.INSTANCE, self());
})
.match(MessageToTheActor.class, msg -> {
log().info("Received message: {}", msg);
// do something with the message...
sender().tell(Ack.INSTANCE, self());
})
.match(StreamCompleted.class, completed -> {
log().info("Stream completed");
})
.match(StreamFailure.class, failed -> {
log().error(failed.getCause(),"Stream failed!");
})
.build();
}
}
要与上述演员一起使用Sink.actorRefWithAck
:
final ActorSystem system = ActorSystem.create("MySystem");
final Materializer materializer = ActorMaterializer.create(system);
ActorRef workerActor = system.actorOf(Props.create(MyWorker.class, "worker"));
Source<MessageToTheActor, NotUsed> messages = Source.repeat(new MessageToTheActor());
Sink<String, NotUsed> sink = Sink.<String>actorRefWithAck(
workerActor,
new StreamInitialized(),
Ack.INSTANCE,
new StreamCompleted(),
ex -> new StreamFailure(ex)
);
messages.runWith(sink, materializer);
请注意使用Source.repeat
,在这种情况下,它会不断发出MessageToTheActor
消息。使用Sink.actorRefWithAck
可确保参与者在处理完当前消息之前不会再收到其他消息。
需要以下导入(显然,Akka Streams依赖项也是如此):
import akka.NotUsed;
import akka.actor.*;
import akka.stream.*;
import akka.stream.javadsl.*;
答案 1 :(得分:1)
调度程序意味着您需要定期进行一些操作,现在,如果second
运行取决于您的first
运行,那么为什么还要创建一个调度程序。
只需创建两个参与者,one manager actor
和另一个child actor
。
当任务为success
时,child actor
向parent actor
发送成功消息,因此父角色要求child actor
再执行一次任务。这样可以保证任务以周期性顺序运行,也可以确保前一个任务成功执行。
因此,基本上,您必须在actors
的接收方法中实现相应的匹配大小写类。
希望这会有所帮助!
答案 2 :(得分:0)
system.scheduler().schedule(
Duration.Zero(),
Duration.create(5, TimeUnit.SECONDS),
workerActor,
new MessageToTheActor(),
system.dispatcher(), ActorRef.noSender());
以上代码表示,调度程序每5秒将message
发送给演员workerActor
。
并且您知道,actor默认仅具有一个线程(除非您使用nr-of-instance> 1进行配置),这意味着发送到workActor
的所有消息都将被缓存在mailbox
中,因为只有一个线程可以调用receive
的{{1}}函数。
换句话说,您可以始终确保仅在当前运行完成时才执行下一次运行,因为默认情况下只有一个线程同时为actor工作。