【Airflow】DAG実行タイミングを改めて纏めてみた

## はじめに
こんにちは。ジールの@________________-_です。

**DAG実行タイミングのクセがスゴイんじゃ**

すいません。これが言いたかっただけです。
DAG実行タイミングをわかったつもりになっていたのですが、
改めてちゃんと理解しようと思い自分用にまとめました。

## 結論
DAG初回実行タイミングは、start_date以降直近のschedule_interval完了時点となる。
それ以降はschedule_intervalが完了する毎に実行される。
これだけだと全くわからないな。。。

## 詳細

DAG実行タイミングは`start_date`と`schedule_interval`を利用して計算される。

- start_date：DAG実行タイミングを計算するための基準となる時間
    - start_dateとschedule_intervalを組み合わせて初回実行タイミングが計算される
- schedule_interval：実行間隔
    - 単純にそのタイミングが来たら実行ではないのでややこしい。。。
    - 主にcron式で実行間隔を定義する

例えば`start_date：2021-2-17 10:00:00 --- schedule_interval：0 11 * * *`だったとき、
直感的に初回タイミングは`2021-2-17 11:00:00`であるが、待てどもDAGが実行されることはない。
初回実行されるのは`2021-2-18 11:00:00`（翌日の11時）である。

どういうことかと言うと、Airflowではintervalの開始ではなく完了時にDAGが実行される仕組みとなっている。
schedule_interval`0 11 * * *`は毎日11時の設定なので、intervalの間隔は当日11時～翌日11時までとなる。
`2021-2-17 11:00:00`は（初回DAG実行タイミングではなく）intervalの開始時間となり、intervalの完了である`2021-2-18 11:00:00`にDAGが実行される。
⇒恐らくここが一番ややこしい（クセがスゴイ）ポイントだと思う。

schedule_intervalは実行開始時間というよりも、intervalという名前どおり間隔と考えた方が分かりやすい。
実行開始時間が点だとすると、schedule_intervalは点ではなく線（intervalの開始と完了を結ぶ線）と捉えた方ががしっくりくる。
そして、繰り返しになるがDAG実行タイミングはschedule_intervalの完了時点となる。
なぜschedule_intervalの開始と完了をしつこく繰り返すかというと、AirflowのwebUI表示もこれまた分かりにくいからだ。

Airflowの表示を確認してみる。
条件は以下の通り。

- airflow Ver：v2.3.0 airflow breezeを利用
- start_date：2022-2-21 8:00:00
- schedule_interval：12 9 * * *
- 初回実行済の状態

まずはDAG一覧表示を確認する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2166013/d4900b47-a48a-0658-affb-345979cedaed.png)

注目点は`Last Run`と`Next Run`である。
Last Runという記載だが実際DAGが実行されたタイミングではない。
これは、前回のschedule_intervalの開始時間である。実際実行されたのはschedule_interval完了時点なので`2022-2-22 9:12:00`である。
また、Next Runも同様次回実行タイミングではない。こちらも次回のschedule_intervalの開始時間である。次回が実行される（予定）のは`2022-2-23 9:12:00`となる。
どちらも表記もintervalの開始を意味しており、実際のDAG実行時間ではない。

次に対象のDAGの実行リストを確認する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2166013/7f42d4a9-358e-b7e4-807e-2153f83e0f56.png)

こちらの注目点は`Logical Date`、`Start Date`、`End Date`である。
※時間表記がUTCとなっているので注意

Logical Dateは、DAG一覧表示のLast Runと同じ時間である。つまり、これはschedule_intervalの開始時間は意味している。
※以前は`Execution Date`という名称だったため更に分かりにくかった。。。Logical Dateに名称変更されて感謝しかない。

Start Date・End Dateは本当のDAG実行時間となる。schedule_intervalが完了して実行された具体的な時間だ。
Logical Dateと比較すると丁度１日ずれているのが分かると思う。schedule_intervalは日次実行で設定している為、
schedule_intervalの完了後（1日後）に丁度実行されているのが確認できる。

改めてDAG実行のタイミングは以下となる。

- start_dateから直近のschedule_intervalが初回interval開始時間（=初回Logical Date）
- 初回intervalの完了時間が初回DAG実行タイミング
- 初回intervalの完了時間は2回目のinterval開始時間（=2回目のLogical Date）
- 2回目のinterval完了時間が2回目のDAG実行タイミング
- 後はこれの繰り返し

## 例

- `start_date：2021-2-17 10:00:00 -- schedule_interval：0 11 * * *`の場合
    - interval開始時間：`2021-2-17 11:00:00`
    - 初回DAG実行タイミング：`2021-2-18 11:00:00`
    - start_dateが10時でintervalが毎日11時なので、10時以降で直近の11時がinterval開始時間の`2021-2-17 11:00:00`。intervalは11時から翌日の11時までなので、interval完了タイミングとなる翌日11時の`2021-2-18 11:00:00`がDAG実行タイミングとなる。

- `start_date：2021-2-17 10:00:00 -- schedule_interval：0 9 * * *`の場合
    - interval開始時間：`2021-2-18 9:00:00`
    - 初回DAG実行タイミング：`2021-2-19 9:00:00`
    - start_dateが10時でintervalが毎日9時なので、10時以降で直近の9時がinterval開始時間となる。start_dateは10時で9時よりも遅い時間の為`2021-2-17`にinterval開始は不可能となる（21日の9時は過ぎている為）。結果、翌日の`2021-2-18 9:00:00`がinterval開始時間となる。intervalは9時から翌日の9時までなので、interval完了タイミングとなる翌日9時の`2021-2-19 9:00:00`がDAG実行タイミングとなる。


## catchupの利用
airflowのcatchupとは、DAGを新しくデプロイした際に過去分の実行が出来る機能のことだ。
`catchup=True`とすることで、過去のDAGが実行される。
具体的には、start_dateから現在(＝DAGをデプロイしてAirflowがDAGを認識したタイミング。正確には違うのかもしれないが一旦そういうていで進める)までのinterval完了分のDAGが順次実行される。
例えば、
- start_date：2021-2-16 10:00:00
- schedule_interval：0 10 * * *  
- 現在(デプロイ時間)：2021-2-18 11:00:00

の場合、
start_dateから計算して完了しているintervalは`2月16日10時～2月17日10時、2月17日10時～2月18日10時`の2回となる。
この過去分2回が自動的に実行される。
`2月18日10時～2月19日10時`のintervalは、現在が`2月18日11時`なのでintervalが完了しておらず対象とはならない。
`2月19日10時`になった時点で（過去分実行ではなく）通常実行される。

では、`catchup=False`の場合はどうなるのか。
結論としては`2月17日10時～2月18日10時`の1回が過去分として実行される。
`catchup=False`は過去分を全く実行しないのではなく、現在(デプロイ時間)での最新のinterval完了分のみ実行する。

catchupを全く実行したくない場合はというと、start_dateを上手く調整して現在(デプロイ時間)時点でintervalが完了しないようにすればよい。
例えば、
- start_date：2021-2-18 10:00:00
- schedule_interval：0 10 * * *  
- 現在(デプロイ時間)：2021-2-18 11:00:00

とすることで、初回のinterval期間が`2月18日10時～2月19日10時`となる。
現在(デプロイ時間)時点でintervalが1つも完了していないので過去分を一切実行されない（実行される過去分が存在しない）。
この時初回実行タイミングは`2月19日10時`となる。

## 改めてまとめ
start_dateとschedule_intervalから初回実行タイミングが計算される。
初回実行以降はschedule_intervalが完了した毎に実行される。

- start_date：DAG実行タイミングを計算するための基準となる時間
- schedule_interval：実行間隔（単純な実行タイミングではないので注意）
- 初回interval開始時間：start_date以降で直近のschedule_interval時間
- 初回interval完了時間：初回schedule_intervalが完了する時間（=次回のschedule_interval開始時間）
- 初回実行タイミング：若干のずれはあるが初回intervalが完了したタイミング
- 初回以降の実行タイミング：初回interval完了時間からschedule_intervalが完了する毎に実行タイミングがくる

## おわりに
慣れると不思議と違和感が無くなっていきますが、初見の時はん？？？と思うのではないでしょうか。
UIの表示も上記を理解していないと。。。ですし。
ただ、Airflow自体は（色々と癖が強いですが）とても良いサービスだと思います。
google cloud・AWSともにAirflowをホストしたサービスが展開されてますし、更に広がっていくと嬉しいです！

## 参照
個人的にはcloud composerの公式ページの説明が分かりやすいと思いました。

https://cloud.google.com/composer/docs/triggering-dags#specify_scheduling_parameters

***
株式会社ジールでは、「ITリテラシーがない」「初期費用がかけられない」「親切・丁寧な支援がほしい」「ノーコード・ローコードがよい」「運用・保守の手間をかけられない」などのお客様の声を受けて、オールインワン型データ活用プラットフォーム「ZEUSCloud」を月額利用料にてご提供しております。
ご興味がある方は是非下記のリンクをご覧ください：
 
https://www.zdh.co.jp/products-services/cloud-data/zeuscloud/?utm_source=qiita&utm_medium=referral&utm_campaign=qiita_zeuscloud_content-area