blog

SpringBootのタイムドタスクと非同期処理

ビジネスをしていると、特定の時間に特定のロジックを実行する、というようなシナリオが常にあります。これは実際、次のようなタイムドタスクのアプリケーションです: 月初にユーザーに先月のデータサマリーを送信...

Mar 25, 2020 · 6 min. read
シェア

時限タスク

特定の時間に特定のロジックを実行する:ビジネスを行う上で、常にそのようなシナリオがあるでしょう。これは、実際に時間指定されたタスクのアプリケーションであり、例えば、前月のデータの要約や他のシナリオを送信するためにユーザーに月の初日の必要性。

テクニック

時間制限のあるタスクを実装するための多くのテクニックがあります。

  • タイマー:JDKはjava.util.Timerが実際にタイマーにもっと似ていますが付属しています、一定の頻度に応じて実装と実行を遅延させることによって達成することができる、また、実行する特定の時間を指定することができます、少ないの使用
  • ScheduledExecutorService: また、JDKに付属しており、特定のタスクを実行するために作成されたエクゼキュータのスレッド数に応じて、時間指定タスククラスのスレッドプールの設計に基づいています。
  • 春タスク:つまり、今日は主人公を紹介するために、春はもちろん、ここでSpringBootの使用を通じて、付属しています。
  • Quartz: より強力な機能を備えたオープンソースのスケジューリングフレームワーク

アノテーションの使用

) @EnableScheduling

スタートアップ・クラスまたは任意のコンフィギュレーション・クラスにマークできる時間制限付きタスクを有効にします。

)@Scheduled

スキャン可能なクラスのメソッドに属性でラベル付けできる特定のタスク実行ルールを設定します:

  • fixedRate: 前のタスクの開始時刻と次のタスクの開始時刻の間隔
  • fixedDelay: 前のタスクの終了時刻から次のタスクの開始時刻までの時間間隔
  • initialDelay: 最初の実行遅延時間。
  • cron: cron式による実行タイミングの設定

cron

時間指定タスクのシナリオ:遅延実行、一定頻度での実行、指定時間での実行

cronは6-7個の要素で構成され、各要素はスペースで区切られています:

  • ~59
  • ~59
  • ~23
  • ~31
  • ~12
  • 第1週~7
  • 年:1970~9029

上記の数値要素値に加えて、以下の特殊要素値があります:

  • *: 任意の値がトリガーされることを示し、7つの要素が分単位のような位置に表示されることができます。
  • ?: は * と似ていますが、曜日と週が意味のある値で設定されている場合にのみ表示されます。
  • -:範囲を示し、7つの要素は、1-7の発生で分などの位置に表示することができます1分から7分まで毎分を実行することを意味します。
  • /:7つの要素の実装は、そのような1 / 7の出現で分のように、位置で表示することができますどのくらいの時間、毎回時間の開始から1 + 7 = 8分トリガ1回1分がトリガされたことを意味することを示します。
  • 例えば、minutesの1,7は、1分と7分がそれぞれ1回ずつ実行されることを意味します。
  • L:最後を意味し、曜日と週の位置にのみ表示されます。曜日は最後の日を意味し、週は5Lのように数字で最後の木曜日を意味します。
  • W:有効営業日を表し、日付にのみ表示され、5Wのように前に数字が付きます:5日が土曜日の場合、4日である金曜日の実行時間、5日が日曜日の場合、6日である次の月曜日の実行時間;
  • LW:最終営業日を示すために併用され、日付にのみ表示されます。
  • #例:4#2は第2水曜日。

上記の式規則はcron式の条件を満たすように書くことができます。

シングルスレッドとマルチスレッドの実行

上記の構成でタスクAとタスクBを記述し、直接実行を開始した場合、以下のような問題が発生します:

  • タスクA1の実行に2秒以上かかる場合、タスクA1の開始から2秒後に実行される予定だったタスクA2は時間通りに実行できません。
  • タスクAとタスクBは交互に実行されます。

上記の問題は、それぞれの実行計画に従ってタスクを実行させることができない、最終的な分析では、またはすべてのタスクは、スレッドで実行されるので、非同期並行実行をしないでください、つまり、マルチスレッドを介してタスク間の非同期並行実行を実現することができます。

ここでは、Springの@Asyncアノテーションを使って、非同期の

非同期

SpringBoot は、非同期の @Async もサポートしています。

注釈

) @EnableAsync

スタートアップ・クラスまたはコンフィギュレーション・クラスにマークされたテーブルは、非同期でオンになります。

) @Async

クラスやメソッドにラベルを付けることができます。

クラス内のメソッドに

非同期メソッドの2つの戻り値

  1. 戻り値なし: void

  2. 戻り値が必要です:

     @Async 
     public Future<String> doTaskOne() throws Exception {
     return new AsyncResult<>("タスク1完了"); 
     } 
    

自動設定

非同期を達成するために@Asyncの使用は、基礎または実装のためのマルチスレッドの使用は、このマルチスレッドまたはスレッドプールは、設定または構成する場所ですか?すべてまでSpringBootは、タスクパッケージのTaskExecutionAutoConfigurationクラスの下に見つけることができるspring-boot-autoconfigureパッケージで、自動設定の多数を追加しました:

@Lazy
@Bean(name = { APPLICATION_TASK_EXECUTOR_BEAN_NAME,
			AsyncAnnotationBeanPostProcessor.DEFAULT_TASK_EXECUTOR_BEAN_NAME })
@ConditionalOnMissingBean(Executor.class)
//このアノテーションの意味:コンテナ内でExecutorクラスが見つからないときにBeanをロードし、デフォルトのデフォルトオブジェクトのためにここにあるように理解することができる
//リターンはスプリングが提供するスレッドプールだ。
	public ThreadPoolTaskExecutor applicationTaskExecutor(TaskExecutorBuilder builder) {
		return builder.build();
	}

TaskExecutorBuilderを見つけます:

@Bean
	@ConditionalOnMissingBean
	public TaskExecutorBuilder taskExecutorBuilder() {
		TaskExecutionProperties.Pool pool = this.properties.getPool();
		TaskExecutorBuilder builder = new TaskExecutorBuilder();
		builder = builder.queueCapacity(pool.getQueueCapacity());
		builder = builder.corePoolSize(pool.getCoreSize());
		builder = builder.maxPoolSize(pool.getMaxSize());
		builder = builder.allowCoreThreadTimeOut(pool.isAllowCoreThreadTimeout());
		builder = builder.keepAlive(pool.getKeepAlive());
		builder = builder.threadNamePrefix(this.properties.getThreadNamePrefix());
		builder = builder.customizers(this.taskExecutorCustomizers.orderedStream()::iterator);
		builder = builder.taskDecorator(this.taskDecorator.getIfUnique());
		return builder;
	}

ここでのプロパティは、TaskExecutionPropertiesでデフォルトのパラメータで読み込まれます:

private int queueCapacity = Integer.MAX_VALUE;
private int coreSize = 8; 
private int maxSize = Integer.MAX_VALUE;
private boolean allowCoreThreadTimeout = true;

以下のように、yml/propertiesファイルから設定をカスタマイズすることも可能です。

@ConfigurationProperties("spring.task.execution")

上記のメソッドに加えて、@ConditionalOnMissingBean(Executor.class)から分かるように、デフォルトのデフォルトBeanを置き換えるために独自のBeanを定義することも可能で、これはコンフィギュレーション・クラスに追加するだけで済みます:

@Bean
 public Executor taskExecutor() {
 ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
 executor.setCorePoolSize(コアスレッド数);
 executor.setMaxPoolSize(最大スレッド数);
 executor.setQueueCapacity(タスクキューのサイズ);
 executor.initialize();
 return executor;
 }

最後に

上記によると、非同期時限タスクを実装するために、@Asyncの追加上記のタスクメソッドを実現するために展開することができます。

Read next

pandas|DataFrameのデータをインデックスで効率的に取得するには?

データの整列\n2つのDataFrameの合計を計算することができますが、データがNanに設定されない場合、pandasは自動的にデータ整列のための2つのDataFrameになります。\nまず、2つのDataFrameを作成します:\nインポート numpy

Mar 25, 2020 · 6 min read