JobRunrという、バッチ処理とかバックグラウンドタスクとかを試してみたんだけど、よくわからない・・・
https://www.jobrunr.io/en/
dependencyにはjobrunrと、あと何かJSONパーサーを入れます。ここではjacksonにしてますが、GSONかyassonでもいいぽい。
<dependency> <groupId>org.jobrunr</groupId> <artifactId>jobrunr</artifactId> <version>6.0.0</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.11.0</version> </dependency>
とりあえず設定。
JobRunr.configure()
.useStorageProvider(new InMemoryStorageProvider())
.useBackgroundJobServer()
.initialize();
Jobを放り込んでみる。
BackgroundJob.enqueue(() -> System.out.println("Hello"));
SLF4Jのログと共に、Helloと表示されました。動いてそう。以降、SLF4Jのログは省略。
SLF4J: No SLF4J providers were found. SLF4J: Defaulting to no-operation (NOP) logger implementation SLF4J: See https://www.slf4j.org/codes.html#noProviders for further details. Hello
ビルダーがあるで、ってことで使ってみる。
BackgroundJob.create(JobBuilder.aJob() .withName("my job") .withDetails(() -> System.out.println("Yeah!!!")));
なんか出てる。よさそう。ここまでは・・・
Hello Yeah!!!
繰り返しタスクを投入してみる。3秒を指定すると5秒以上にしろと怒られたので、5秒にする。
BackgroundJob.scheduleRecurrently(Duration.ofSeconds(5), () -> System.out.println("Yooo!!!"));
なんか3つずつ出てくる。
Yooo!!! Yeah!!! Yooo!!! Yooo!!! Hello Yooo!!! Yooo!!! Yooo!!!
ちょっと時間を同時に表示しようとLocalTime.now()
を付け加える。
BackgroundJob.scheduleRecurrently(Duration.ofSeconds(5), () -> System.out.println("Yooo!!! %s".formatted(LocalTime.now())));
全部同じ時刻だ・・・どういうこと?
Yooo!!! 12:15:34.239878800 Hello Yeah!!! Yooo!!! 12:15:34.239878800 Yooo!!! 12:15:34.239878800 Yooo!!! 12:15:34.239878800 Yooo!!! 12:15:34.239878800 Yooo!!! 12:15:34.239878800
カウンターを付け加えてみる。
int[] count = {0}; BackgroundJob.scheduleRecurrently(Duration.ofSeconds(5), () -> System.out.println("Yooo!!!(%d) %s" .formatted(count[0]++, LocalTime.now())));
死んだ・・・・
Exception in thread "main" org.jobrunr.JobRunrException: JobRunr encountered a problematic exception. Please create a bug report (if possible, provide the code to reproduce this and the stacktrace) at org.jobrunr.JobRunrException.shouldNotHappenException(JobRunrException.java:43) at org.jobrunr.jobs.details.instructions.AllJVMInstructions.get(AllJVMInstructions.java:82) at org.jobrunr.jobs.details.AbstractJobDetailsFinder$1.visitInsn(AbstractJobDetailsFinder.java:46) at org.objectweb.asm.ClassReader.readCode(ClassReader.java:2213) at org.objectweb.asm.ClassReader.readMethod(ClassReader.java:1514) at org.objectweb.asm.ClassReader.accept(ClassReader.java:744) ...
結局、scheduleRecurrently
メソッドなどでジョブ登録するラムダ式は、直接よびだされるのではなくてシリアライズされたあとで復元されて呼び出されるぽい。ので、ラムダの中で計算をしてはダメで、メソッド呼び出してそっちでいろいろやるべきってことらしい。
ということでメソッドを定義する。このとき、このメソッドはJobRunrの内部から呼び出されるのでpublic
である必要がある。
static int count = 0; public static void some() { System.out.println("Yooo![%d] %s".formatted(++count, LocalTime.now())); }
で呼び出しジョブを登録する。
BackgroundJob.scheduleRecurrently(Duration.ofSeconds(5),
() -> some());
いい感じ
Yooo![1] 12:41:48.847377500 Yooo![2] 12:41:48.859376600 Yooo![3] 12:41:48.887877700 Yooo![4] 12:42:03.937876600 Yooo![5] 12:42:03.986377300 Yooo![6] 12:42:04.018877300
あと、15秒ごとに呼び出されて3回実行しているので、まあ5秒ごとに3回というのが間に合わなかったという感じっぽい。
最後に、useBackgroundJobServer()
を設定しておくと、ダッシュボードが表示できる。
JobRunr.configure() .useStorageProvider(new InMemoryStorageProvider()) .useBackgroundJobServer() .useDashboard(8000) .initialize();
現実的には、@Job
アノテーションでジョブを指定することが多そうなので問題はない気がするけど、ちょっと遊ぼうとして雑に呼び出すとハマるという話。