⛄️

DaprのアクターでタイマーとリマインダーをJava SDKで使う

2022/01/04に公開

概要

前回の記事がこちら。

https://zenn.dev/backpaper0/articles/b670dd72c5eb04

今回はやり残していたタイマーとリマインダーを見てみます。

タイマーとリマインダーの簡単な説明

https://docs.dapr.io/developing-applications/building-blocks/actors/howto-actors/#actor-timers-and-reminders

タイマーとリマインダーは両方ともアクターの作業をスケジューリングできる機能です。
1度きりの作業と定期的な作業、どちらもスケジューリングできます。

タイマーとリマインダーの違いはスケジューリング後にアクターが非アクティブ化されたときの挙動です。
時間が来た際にアクターが非アクティブ状態の場合、タイマーは動作しませんがリマインダーはアクターをアクティベートして動作してくれます。
リマインダーは状態ストアにスケジュールを保存することでこれを実現しています。
公式ドキュメントによると、軽量でステートレスなタイマーとより多くのリソースを必要とするステートフルなリマインダー、といった表現がされています。

コンテナが落ちてスケジュールが失われても良い場合は軽量なタイマーを、そういった場合でも確実に実行したい場合はリマインダーを、といった使い分けになりそうです。

タイマーとリマインダーをJava SDKで使う方法

アクターの基底クラスであるio.dapr.actors.runtime.AbstractActorに次の2つのメソッドがあり、それぞれタイマーの登録・解除、リマインダーの登録・解除ができます。

  • registerActorTimer
  • unregisterTimer
  • registerReminder
  • unregisterReminder

タイマーの登録

registerActorTimerは5つの引数を取ります。

引数名 説明
timerName String タイマーの名前。nullの場合、自動生成される。
callback String 時間が来たら呼び出されるコールバックメソッドの名前。
state 型変数T スケジュールされたコールバックメソッドへ渡す引数。
dueTime java.time.Duration コールバックメソッドの初回呼び出しまでの遅延時間。Duration.ZEROを渡すと即時呼び出しされる。
period java.time.Duration コールバックメソッドを定期的に呼び出す間隔。Duration.ofMillis(-1L)を渡すと定期的な呼び出しはされない。

戻り値はMono<String>でタイマーの名前が返ってきます。
自動生成された場合はこの戻り値で取得できるわけですね。

コード例は次の通り。

public class TimerDemoActorImpl extends AbstractActor
        implements TimerDemoActor {

    @Override
    public Mono<String> doLater(String state) {
        // 10分後にhandleDoLaterメソッドを呼び出す。
        // その後、30分毎にhandleDoLaterメソッドを呼び出す。
        return registerActorTimer(null, "handleDoLater", state,
                Duration.ofMinutes(10), Duration.ofMinutes(30));
    }

    @Override
    public void handleDoLater(String state) {
        // 遅延実行される。
    }
}

リマインダーの登録

registerReminderは4つの引数を取ります。

引数名 説明
reminderName String リマインダーの名前。タイマーとは異なりnullを渡しても自動生成されない。
state 型変数T タイマーと同じ。
dueTime java.time.Duration タイマーと同じ。
period java.time.Duration タイマーと同じ。

戻り値はMono<Void>です。

リマインダーはコールバックメソッドを指定しませんが、その代わりにアクターがio.dapr.actors.runtime.Remindableimplementsする必要があります。
RemindablereceiveReminderがコールバックメソッドになります。
複数種類のリマインダーを登録したい場合、receiveReminderに渡されるリマインダーの名前で処理を分岐させることになりそうです。

コード例は次の通り。

public class ReminderDemoActorImpl extends AbstractActor
        implements ReminderDemoActor, Remindable<String> {

    @Override
    public Mono<Void> doLater(String state) {
        // 10分後にreceiveReminderメソッドを呼び出す。
        // その後、30分毎にreceiveReminderメソッドを呼び出す。
        return registerReminder("demo", state,
                Duration.ofMinutes(10), Duration.ofMinutes(30));
    }

    @Override
    public TypeRef<String> getStateType() {
        // Remindableで宣言されているメソッド。
        // リマインダーが受け取るステートの型。
        return TypeRef.get(String.class);
    }

    @Override
    public Mono<Void> receiveReminder(String reminderName, String state,
            Duration dueTime, Duration period) {
        // Remindableで宣言されているメソッド。
        // 遅延実行される。
    }
}

タイマーとリマインダーの解除

unregisterTimerメソッドへタイマー名を渡して呼び出せばタイマーを解除できます。

unregisterReminderメソッドへリマインダー名を渡して呼び出せばリマインダーを解除できます。

以上です。

Discussion