アクターのタイマーとアラーム
アクターは、タイマーまたはアラームを登録することで、自身の定期的な作業をスケジュールできます。 ここでは、タイマーとアラームの使用方法と、これらの違いについて説明します。
アクターのタイマー
アクターのタイマーは、アクターのランタイムが提供するターンごとのコンカレンシーの保証を、コールバック メソッドが考慮するように、.NET タイマーまたは Java タイマーの単純なラッパーを提供します。
アクターは、その基本クラスに RegisterTimer
(C#) または registerTimer
(Java) および UnregisterTimer
(C#) または unregisterTimer
(Java) のメソッドを使用して、タイマーを登録/登録解除できます。 次の例はタイマー API の使用を示します。 API は、.NET タイマーまたは Java タイマーによく似ています。 この例では、タイマーが期限に達すると、アクターのランタイムが MoveObject
(C#) または moveObject
(Java) メソッドを呼び出します。 このメソッドは、ターンごとのコンカレンシーを優先することを保証します。 つまり、このコールバックの実行が完了するまで、他のアクター メソッドやタイマーとアラームのコールバックは進行しません。
class VisualObjectActor : Actor, IVisualObject
{
private IActorTimer _updateTimer;
public VisualObjectActor(ActorService actorService, ActorId actorId)
: base(actorService, actorId)
{
}
protected override Task OnActivateAsync()
{
...
_updateTimer = RegisterTimer(
MoveObject, // Callback method
null, // Parameter to pass to the callback method
TimeSpan.FromMilliseconds(15), // Amount of time to delay before the callback is invoked
TimeSpan.FromMilliseconds(15)); // Time interval between invocations of the callback method
return base.OnActivateAsync();
}
protected override Task OnDeactivateAsync()
{
if (_updateTimer != null)
{
UnregisterTimer(_updateTimer);
}
return base.OnDeactivateAsync();
}
private Task MoveObject(object state)
{
...
return Task.FromResult(true);
}
}
public class VisualObjectActorImpl extends FabricActor implements VisualObjectActor
{
private ActorTimer updateTimer;
public VisualObjectActorImpl(FabricActorService actorService, ActorId actorId)
{
super(actorService, actorId);
}
@Override
protected CompletableFuture onActivateAsync()
{
...
return this.stateManager()
.getOrAddStateAsync(
stateName,
VisualObject.createRandom(
this.getId().toString(),
new Random(this.getId().toString().hashCode())))
.thenApply((r) -> {
this.registerTimer(
(o) -> this.moveObject(o), // Callback method
"moveObject",
null, // Parameter to pass to the callback method
Duration.ofMillis(10), // Amount of time to delay before the callback is invoked
Duration.ofMillis(timerIntervalInMilliSeconds)); // Time interval between invocations of the callback method
return null;
});
}
@Override
protected CompletableFuture onDeactivateAsync()
{
if (updateTimer != null)
{
unregisterTimer(updateTimer);
}
return super.onDeactivateAsync();
}
private CompletableFuture moveObject(Object state)
{
...
return this.stateManager().getStateAsync(this.stateName).thenCompose(v -> {
VisualObject v1 = (VisualObject)v;
v1.move();
return (CompletableFuture<?>)this.stateManager().setStateAsync(stateName, v1).
thenApply(r -> {
...
return null;});
});
}
}
タイマーの次の期間は、コールバックが実行を完了した後に開始します。 これは、コールバックを実行している間はタイマーが停止し、コールバックが完了したときにタイマーが開始することを意味します。
コールバックが完了すると、アクターのランタイムは、アクターの状態マネージャーに加えられた変更を保存します。 状態の保存中にエラーが発生した場合、そのアクターのオブジェクトは非アクティブ化し、新しいインスタンスがアクティブ化されます。
リマインダーとは異なり、タイマーを更新することはできません。 RegisterTimer
が再度呼び出されると、新しいタイマーが登録されます。
ガベージ コレクションの一部としてアクターが非アクティブ化されると、すべてのタイマーが停止します。 その後は、タイマーのコールバックは呼び出されません。 また、アクターのランタイムは、非アクティブ化の前に実行されていたタイマーについての情報は保持しません。 その後、再アクティブ化したときに必要なタイマーを登録するかどうかはアクターによって異なります。 詳細については、「 アクターのガベージ コレクション」のセクションを参照してください。
アクターのアラーム
アラームは、指定した時間にアクターに永続的なコールバックをトリガーするメカニズムです。 タイマーと似ていますが、アラームの場合は、アクターが明示的にアラームの登録を解除するか、アクターが明示的に削除されるまで、あらゆる状況下でトリガーされます。 具体的には、アラームはアクターの無効化およびフェールオーバーによりトリガーされます。 これは、アクターのランタイムが、アクター状態プロバイダーを使用してアクターのアラームに関する情報を永続化するためです。 また、タイマーとは異なり、既存のアラームを更新するには、同じ reminderName を使用して登録メソッド (RegisterReminderAsync
) を再度呼び出します。
Note
アラートの信頼性は、アクター状態プロバイダーが提供する状態の信頼性の保証に関連付けられています。 つまり、状態の永続性が "なし" に設定されているアクターの場合、フェールオーバー後にアラートが起動しません。
アラームを登録するには、次の例に示すように、アクターが基本クラスで提供される RegisterReminderAsync
メソッドを呼び出します。
protected override async Task OnActivateAsync()
{
string reminderName = "Pay cell phone bill";
int amountInDollars = 100;
IActorReminder reminderRegistration = await this.RegisterReminderAsync(
reminderName,
BitConverter.GetBytes(amountInDollars),
TimeSpan.FromDays(3), //The amount of time to delay before firing the reminder
TimeSpan.FromDays(1)); //The time interval between firing of reminders
}
@Override
protected CompletableFuture onActivateAsync()
{
String reminderName = "Pay cell phone bill";
int amountInDollars = 100;
ActorReminder reminderRegistration = this.registerReminderAsync(
reminderName,
state,
dueTime, //The amount of time to delay before firing the reminder
period); //The time interval between firing of reminders
}
上記の例で、 "Pay cell phone bill"
はアラーム名です。 これは、アクターがアラームを一意に識別するために使用する文字列です。 BitConverter.GetBytes(amountInDollars)
(C#) は、そのアラームに関連付けられているコンテキストです。 これは、アラームのコールバックの引数、つまり IRemindable.ReceiveReminderAsync
(C#) または Remindable.receiveReminderAsync
(Java) としてアクターに戻ります。
アラームを使用するアクターは、次の例に示すように IRemindable
インターフェイスを実装する必要があります。
public class ToDoListActor : Actor, IToDoListActor, IRemindable
{
public ToDoListActor(ActorService actorService, ActorId actorId)
: base(actorService, actorId)
{
}
public Task ReceiveReminderAsync(string reminderName, byte[] context, TimeSpan dueTime, TimeSpan period)
{
if (reminderName.Equals("Pay cell phone bill"))
{
int amountToPay = BitConverter.ToInt32(context, 0);
System.Console.WriteLine("Please pay your cell phone bill of ${0}!", amountToPay);
}
return Task.FromResult(true);
}
}
public class ToDoListActorImpl extends FabricActor implements ToDoListActor, Remindable
{
public ToDoListActor(FabricActorService actorService, ActorId actorId)
{
super(actorService, actorId);
}
public CompletableFuture receiveReminderAsync(String reminderName, byte[] context, Duration dueTime, Duration period)
{
if (reminderName.equals("Pay cell phone bill"))
{
int amountToPay = ByteBuffer.wrap(context).getInt();
System.out.println("Please pay your cell phone bill of " + amountToPay);
}
return CompletableFuture.completedFuture(true);
}
アラームがトリガーされると、Reliable Actors のランタイムがアクターの ReceiveReminderAsync
(C#) メソッドまたは receiveReminderAsync
(Java) メソッドを呼び出します。 アクターは複数のアラームを登録でき、そのいずれかのアラームがトリガーされると、ReceiveReminderAsync
(C#) メソッドまたは receiveReminderAsync
(Java) メソッドが呼び出されます。 アクターは ReceiveReminderAsync
(C#) メソッドまたは receiveReminderAsync
(Java) メソッドに渡されるアラーム名を使用して、どのアラームがトリガーされたかを判別します。
アクターのランタイムは、ReceiveReminderAsync
(C#) または receiveReminderAsync
(Java) の呼び出しが完了すると、アクターの状態を保存します。 状態の保存中にエラーが発生した場合、そのアクターのオブジェクトは非アクティブ化し、新しいインスタンスがアクティブ化されます。
アラームの登録を解除するには、次の例に示すように、アクターが UnregisterReminderAsync
(C#) メソッドまたは unregisterReminderAsync
(Java) メソッドを呼び出します。
IActorReminder reminder = GetReminder("Pay cell phone bill");
Task reminderUnregistration = await UnregisterReminderAsync(reminder);
ActorReminder reminder = getReminder("Pay cell phone bill");
CompletableFuture reminderUnregistration = unregisterReminderAsync(reminder);
上記の例のように、UnregisterReminderAsync
(C#) メソッドまたは unregisterReminderAsync
(Java) メソッドは、IActorReminder
(C#) インターフェースまたは ActorReminder
(Java) インターフェイスを受け入れます。 アクターの基本クラスは、アラーム名で渡すことで、IActorReminder
(C#) インターフェイスまたは ActorReminder
(Java) インターフェイスを取得できる GetReminder
(C#) メソッドまたは getReminder
(Java) メソッドをサポートします。 これにより、アクターが RegisterReminder
(C#) メソッドまたは registerReminder
(Java) メソッドの呼び出しから返された IActorReminder
(C#) インターフェイスまたは ActorReminder
(Java) インターフェイスを永続化する必要がなくなるため便利です。
次の手順
Reliable Actor のイベントと再入について学習します。