---
title: "データパイプライン自動化の実装：Airflowのアセット起動・イベント駆動とdbtのCIで手作業をなくす手順【2026年版】"
url: "https://www.issoh.co.jp/tech/details/19625/"
published: 2026-11-12
updated: 2026-11-12
categories: ["AI"]
publisher: "株式会社一創"
---

# データパイプライン自動化の実装：Airflowのアセット起動・イベント駆動とdbtのCIで手作業をなくす手順【2026年版】

データパイプライン自動化で人の手から外すべきものは、ジョブの実行ボタンだけではありません。「上流が終わったか確認してから流す」「落ちたら朝に再実行する」「SQLを直したら本番で試す」という3つの作業が残っている限り、自動化はまだ半分までの状態です。本記事では、Airflow 3.4系とdbt Core 1.12系（いずれも2026年11月時点の最新）を使い、時刻起動・データ起動・イベント起動・変更起動の4つをコード付きで実装します。最後に、オーケストレーターを入れずにcronで済ませるべき条件も示します。

## まとめ：データパイプライン自動化は時刻起動から始めデータ起動とCIへ広げる

最初に入れるのは、リトライ付きの時刻起動です。Airflowの`retries`と`retry_exponential_backoff`を設定するだけで、一時的な接続エラーによる朝の手動再実行はほぼ消えます。

次に、cronの時刻ずらしで上流と下流をつないでいる箇所をAssetによるデータ起動へ置き換えます。ファイル到着が不定期な取り込みにはS3からSQS経由のイベント起動を、SQLの変更にはdbtの`state:modified+`で変更分だけを検証するCIを足してください。テーブルが数本で日次1回の更新なら、ここまでは不要です。cronと1本のスクリプトで止めます。

## データパイプライン自動化で人の手から外す4つの起点とcronだけで組んだ構成の事故

実装の前に、どの作業を機械に渡すのかを棚卸しします。抜けやすいのは、実行そのものより「実行してよいかの判断」です。

### 時刻・データ・イベント・変更の4起点で手作業の残る箇所を棚卸しする表

パイプラインの起動のきっかけは4種類に分けられます。本記事で実装する範囲と対応させると次のとおりです。変更起動の行では、dbtのstate:modified+による変更分の選択とGitHub ActionsでのCI実行を組み合わせます。

| 起点   | 残りがちな手作業    | 自動化の手段         | 本記事の実装                |
| ---- | ----------- | -------------- | --------------------- |
| 時刻   | 失敗時の手動再実行   | スケジュール＋リトライ    | retries・backoff       |
| データ  | 上流の完了確認     | 上流の出力を合図に起動    | Asset（outlets）        |
| イベント | ファイル到着の確認   | 外部キューのメッセージで起動 | S3通知＋SQS＋AssetWatcher |
| 変更   | SQL修正後の本番確認 | プルリクエストで検証     | dbt＋GitHub Actions    |

取込・変換・配信という層の分け方そのものは[データパイプラインとは](https://www.issoh.co.jp/tech/details/15848/)で整理しています。本記事は、その各層を「誰も触らずに動く」状態にする手順に絞ります。

### cronの時刻ずらしで依存をつなぐ構成が上流の遅延で静かに壊れる仕組み

よくある構成は、取り込みを2時、変換を3時、集計を4時にcronで並べる形です。上流が1時間遅れた日、変換は前日のデータのまま3時に成功します。終了コードは0なので、誰も気づきません。

時刻の間隔を広げても解決しません。遅延の上限は誰にも分からず、間隔を広げた分だけ毎日の鮮度が落ちます。必要なのは「上流が書き終えたこと」を起動条件にする仕組みで、それが次章以降のデータ起動とイベント起動です。壊れたことを検知する側の実装は[データパイプライン監視の実装](https://www.issoh.co.jp/tech/details/19623/)で扱っています。

## 検証環境を整えAirflow 3.4系のスケジュールとリトライで日次処理を自動化する手順

最初の自動化は時刻起動です。DAGの基本的な書き方と環境構築は[Apache Airflowとは](https://www.issoh.co.jp/tech/details/1441/)で済ませている前提で進めます。

### Airflow 3.4.0とdbt Core 1.12.6を入れる検証環境の構築コマンド

[PyPIのapache-airflow](https://pypi.org/project/apache-airflow/)では2026年11月6日公開の3.4.0が、[dbt-core](https://pypi.org/project/dbt-core/)では10月14日公開の1.12.6が最新です。イベント起動で使うメッセージキュー用のproviderも、この時点で一緒に入れます。

```
python -m venv .venv
source .venv/bin/activate
pip install "apache-airflow==3.4.0" \
  "apache-airflow-providers-common-messaging[amazon]" \
  "dbt-core==1.12.6" dbt-postgres
airflow standalone
```

[common.messagingの公式ページ](https://airflow.apache.org/docs/apache-airflow-providers-common-messaging/stable/index.html)では、このproviderが対応する最小のAirflowは3.0.1で、`amazon` extraを付けるとAmazon providerが一緒に入ると案内されています。本番ではAirflow公式の制約ファイルを使い、依存の版を固定してください。

### retriesとcatchupを明示した日次DAGで朝の手動再実行をなくすコード

次のDAGは毎日2時（日本時間）に取り込みとdbtのビルドを流します。一時的なエラーは間隔を延ばしながら3回まで再試行し、過去分の一斉実行は止めています。

```
from datetime import timedelta

import pendulum
from airflow.providers.standard.operators.bash import BashOperator
from airflow.sdk import DAG

default_args = {
    "retries": 3,
    "retry_delay": timedelta(minutes=5),
    "retry_exponential_backoff": True,
    "max_retry_delay": timedelta(minutes=30),
}

with DAG(
    dag_id="daily_orders",
    schedule="0 2 * * *",
    start_date=pendulum.datetime(2026, 11, 1, tz="Asia/Tokyo"),
    catchup=False,
    max_active_runs=1,
    default_args=default_args,
):
    extract = BashOperator(
        task_id="extract_orders",
        bash_command="python /opt/jobs/extract_orders.py --date {{ ds }}",
    )
    transform = BashOperator(
        task_id="dbt_build",
        bash_command="cd /opt/dbt && dbt build --select tag:orders",
    )
    extract >> transform
```

押さえる設定は3つです。`catchup=False`は、停止していた期間の実行を再開時にまとめて流さないための指定で、既定値に頼らない明示的な指定です。`max_active_runs=1`は前日の実行が終わる前に翌日分が走るのを防ぎます。取り込みスクリプトに`{{ ds }}`（論理日付）を渡しておくと、特定日だけの再実行がUIから1クリックで済みます。

## Assetで上流の更新完了を合図に下流を動かすデータ起動の自動化を実装する

cronの時刻ずらしを、上流の書き込み完了を合図にする起動へ置き換えます。Airflow 3系ではこの仕組みをAssetと呼びます。

### outletsとschedule=\[asset\]で取込・変換DAGをつなぐ実装コード

[Asset-Aware Schedulingの公式ドキュメント](https://airflow.apache.org/docs/apache-airflow/stable/authoring-and-scheduling/asset-scheduling.html)の形に沿って、取り込み側のタスクに`outlets`を、変換側のDAGの`schedule`に同じAssetを指定します。

```
import pendulum
from airflow.providers.standard.operators.bash import BashOperator
from airflow.sdk import DAG, Asset

raw_orders = Asset("s3://raw-bucket/orders/")

with DAG(
    dag_id="ingest_orders",
    schedule="0 2 * * *",
    start_date=pendulum.datetime(2026, 11, 1, tz="Asia/Tokyo"),
    catchup=False,
):
    BashOperator(
        task_id="load_raw_orders",
        bash_command="python /opt/jobs/load_orders.py",
        outlets=[raw_orders],
    )

with DAG(
    dag_id="transform_orders",
    schedule=[raw_orders],
    start_date=pendulum.datetime(2026, 11, 1, tz="Asia/Tokyo"),
    catchup=False,
):
    BashOperator(
        task_id="dbt_build_orders",
        bash_command="cd /opt/dbt && dbt build --select source:raw.orders+",
    )
```

`load_raw_orders`が成功した時点でAssetの更新が記録され、`transform_orders`が起動します。取り込みが失敗した日は変換も走らないため、前日データのまま成功する事故が構造的に起きません。Assetの文字列はURIの形をとりますが、Airflowはその場所を見に行くわけではなく、更新の記録を照合する識別子として扱います。

### 複数の上流がそろったら起動するAND条件とどちらかで起動するOR条件の書き分け

集計テーブルが受注と在庫の両方に依存するなら、2つのAssetがそろうまで待たせます。公式ドキュメントの記法では`&`がAND、`|`がORです。

```
orders = Asset("s3://raw-bucket/orders/")
stock = Asset("s3://raw-bucket/stock/")
returns = Asset("s3://raw-bucket/returns/")

# 受注と在庫の両方が更新されたら起動
with DAG(dag_id="build_sales_mart", schedule=(orders & stock), ...):
    ...

# 受注か返品のどちらかが更新されたら起動
with DAG(dag_id="refresh_order_events", schedule=(orders | returns), ...):
    ...
```

使い分けの基準は、下流が「全部そろわないと誤った数字を出すか」です。売上と在庫を突き合わせる集計はAND、イベントを追記するだけのテーブルはORで足ります。上流が5本を超えてAND条件が長くなったら、依存の設計そのものを見直す時期です。アセットを中心に依存を定義する考え方を突き詰めたツールとして[Dagster](https://www.issoh.co.jp/tech/details/15948/)があり、選び方は最後の章で触れます。

## S3へのファイル到着をSQS経由で受けてDAGを起動するイベント駆動の実装

取引先がCSVを置く時刻が日によって違うなら、時刻起動もデータ起動も合いません。ファイル到着そのものを起点にします。

### S3イベント通知をSQSへ送りAssetWatcherで待ち受ける設定とDAGのコード

手順は3段です。SQSのアクセスポリシーでS3からの送信を許可し、バケットに通知設定を入れ、Airflow側でキューを監視します。権限のポリシー例は[S3の公式ドキュメント](https://docs.aws.amazon.com/AmazonS3/latest/userguide/grant-destinations-permissions-to-s3.html)にあり、`Principal`に`s3.amazonaws.com`、条件に`aws:SourceArn`と`aws:SourceAccount`を指定する形です。通知設定は次のとおりです。

```
cat > notify.json <<'EOF'
{
  "QueueConfigurations": [
    {
      "QueueArn": "arn:aws:sqs:ap-northeast-1:123456789012:orders-arrival",
      "Events": ["s3:ObjectCreated:*"],
      "Filter": {"Key": {"FilterRules": [{"Name": "prefix", "Value": "incoming/"}]}}
    }
  ]
}
EOF
aws s3api put-bucket-notification-configuration \
  --bucket partner-upload-bucket \
  --notification-configuration file://notify.json
```

[S3の通知設定の解説](https://docs.aws.amazon.com/AmazonS3/latest/userguide/how-to-enable-disable-notification-intro.html)によると、設定の反映にはおよそ5分かかり、有効化した直後に`s3:TestEvent`が1通届きます。Airflow側は[common.messagingの公式例](https://airflow.apache.org/docs/apache-airflow-providers-common-messaging/stable/triggers.html)と同じく、`MessageQueueTrigger`をAssetの監視役に付けます。

```
from airflow.providers.common.messaging.triggers.msg_queue import MessageQueueTrigger
from airflow.providers.standard.operators.bash import BashOperator
from airflow.sdk import DAG, Asset, AssetWatcher

trigger = MessageQueueTrigger(
    scheme="sqs",
    sqs_queue="https://sqs.ap-northeast-1.amazonaws.com/123456789012/orders-arrival",
)
partner_files = Asset(
    "partner_orders_arrival",
    watchers=[AssetWatcher(name="orders_arrival_watcher", trigger=trigger)],
)

with DAG(dag_id="load_partner_orders", schedule=[partner_files]):
    BashOperator(
        task_id="load_new_files",
        bash_command="python /opt/jobs/load_partner_files.py --prefix incoming/",
    )
```

AWSへの接続には既定の接続ID`aws_default`が使われます。このイベント駆動スケジューリングは[Airflowの公式ドキュメント](https://airflow.apache.org/docs/apache-airflow/stable/authoring-and-scheduling/event-scheduling.html)で3.0から追加された機能と明記されており、2系の環境では使えません。最初に届く`s3:TestEvent`でもDAGが1回起動するので、取り込み処理は「対象ファイルが無ければ何もせず正常終了する」作りにしておきます。

### イベント駆動で起きる二重起動と再配信に備える冪等な書き込みの型

[S3のイベント通知](https://docs.aws.amazon.com/AmazonS3/latest/userguide/EventNotifications.html)は「少なくとも1回」届く設計で、通常は数秒、ときに1分以上遅れると公式に書かれています。同じファイルの通知が2回届くことを前提とした実装が必要です。Airflow側でも、トリガーの再起動後にブローカーが再配信する場合があるため、受け手を冪等にするよう公式ドキュメントが求めています。

実装の型は2つです。1つは、ファイルのキーとETagを取り込み済み台帳のテーブルに記録し、記録済みなら読み飛ばす方法。もう1つは、取り込み先を日付パーティションごとに上書きする方法で、何度流しても結果が同じになります。追記型のテーブルにそのまま`INSERT`する設計は、イベント駆動とは組み合わせないでください。なお、S3の通知先にFIFOキューは指定できません。順序を保証したい場合はEventBridge経由にするとAWSは案内しています。

## dbtのstate:modified+とGitHub Actionsで変更分を検証するCI

4つ目の起点は、SQLの変更です。変換処理を直した人が本番で流して確かめる運用は、それ自体が手作業の自動化漏れです。dbtのプロジェクト構成とCIの基本は[dbt Coreの使い方](https://www.issoh.co.jp/tech/details/19592/)にまとめています。

### 本番のmanifestと比べて変更モデルと下流だけをビルドするコマンド

dbtは、前回の実行で出力した成果物（`target/`配下のmanifest）と今のコードを比べ、新規・変更されたモデルを選べます。[dbtの公式ドキュメント](https://docs.getdbt.com/reference/node-selection/configure-state)の形に沿うと、コマンドは次のとおりです。

```
# 本番ジョブの最後に成果物を保存しておく
aws s3 cp target/manifest.json s3://dbt-artifacts/prod/manifest.json

# CIでは本番のmanifestを取得し、変更モデルとその下流だけをビルドする
aws s3 cp s3://dbt-artifacts/prod/manifest.json prod-artifacts/manifest.json
dbt build --select state:modified+ --defer --state prod-artifacts --target ci
```

`--defer`を付けると、変更していない上流モデルはCI用スキーマに作らず本番のテーブルを参照します。[deferの公式解説](https://docs.getdbt.com/reference/node-selection/defer)では、この組み合わせの呼び名は「Slim CI」です。モデルが200本あってもCIで作るのは変更した数本とその下流だけになり、実行時間とDWHの費用が下がります。`--state`に渡す成果物は、実行中のdbtと互換性のあるスキーマの版が条件です。本番とCIでdbtの版をそろえてください。

### プルリクエストで変換処理を検証するGitHub Actionsのワークフロー定義

上のコマンドを、プルリクエストのたびに自動で走らせます。接続情報はリポジトリのSecretsに入れ、`profiles.yml`から環境変数で読ませる前提です。

```
name: dbt-slim-ci
on:
  pull_request:
    paths: ["models/**", "macros/**", "dbt_project.yml"]

jobs:
  build-changed:
    runs-on: ubuntu-latest
    env:
      DBT_CI_PASSWORD: ${{ secrets.DBT_CI_PASSWORD }}
      AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
      AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.12"
      - run: pip install "dbt-core==1.12.6" dbt-postgres
      - run: aws s3 cp s3://dbt-artifacts/prod/manifest.json prod-artifacts/manifest.json
      - run: dbt deps
      - run: dbt build --select state:modified+ --defer --state prod-artifacts --target ci
```

テストが1本でも落ちればプルリクエストに赤い印が付き、マージ前に止まります。どのテストを書くかは[dbt testの書き方](https://www.issoh.co.jp/tech/details/19611/)で、generic・singular・unit testの使い分けとして整理しています。CI用スキーマはプルリクエストごとに名前を分けると、同時に複数の変更を検証しても衝突しません。

### GitHub Actionsのscheduleで本体を起動しない理由と起動処理の配置先

CIと同じ場所で本番の定時実行も済ませたくなりますが、勧めません。[GitHubの公式ドキュメント](https://docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows)は、`schedule`イベントについて次の制約を明記しています。

- 高負荷時、特に毎時0分前後は実行が遅れ、負荷が十分に高いとキューのジョブが破棄されることがある
- 最短の間隔は5分で、時刻はUTC基準
- 既定ブランチでしか動かない
- 公開リポジトリでは60日間活動が無いと自動で無効になる

「破棄されることがある」起動は、業務データの定時更新には使えません。GitHub Actionsは変更起動（プルリクエストのCI）に限定し、時刻・データ・イベント起動はAirflowなどのオーケストレーターに置く、という役割分担で固定します。

## 自動化の範囲を決める判断基準とオーケストレーターを入れずに済ませる条件

4つの起点をすべて自動化する必要はありません。データの届き方と規模で、入れる範囲を決めます。

### 時刻起動・データ起動・イベント起動のどれを選ぶかを決める判断表

起動方式は、上流の終わり方とデータの届き方で決まります。

| 状況               | 選ぶ起動方式       | 理由                |
| ---------------- | ------------ | ----------------- |
| 外部APIから決まった時刻に取得 | 時刻起動＋リトライ    | 取得のタイミングを自社で決められる |
| 社内の上流ジョブの完了後に変換  | データ起動（Asset） | 上流の遅延にそのまま追従できる   |
| 取引先のファイル到着が不定期   | イベント起動（SQS）  | 到着時刻を予測できない       |
| 秒単位の鮮度が必要        | ストリーミング基盤    | DAGの起動単位では間に合わない  |

最後の行に当たる場合、Airflowのイベント起動は解になりません。DAGの起動と終了の間隔は秒単位の要件に向かないため、Kafkaなどのストリーミング処理を別に設計します。処理方式の選び分けは[データパイプラインとは](https://www.issoh.co.jp/tech/details/15848/)のバッチ・ストリーミング・CDCの章を参照してください。

### テーブルが数本で日次1回ならcronと1本のスクリプトで止めるべき場面

Airflowを本番で動かすと、スケジューラ・Webサーバ・メタデータDBの3つを保守する仕事が増えます。次の条件が全部そろうなら、オーケストレーターは過剰です。

- 連携するテーブルが10本未満で、上流と下流の依存が1段だけ
- 更新は日次1回で、遅れても当日中に直せば業務が回る
- データの担当者が1人で、変更の頻度が月に数回

この規模では、cronから1本のシェルスクリプトを呼び、取り込みとdbtのビルドを`&&`でつなげば足ります。上流が失敗したら後続が走らない点は、Assetと同じ効果です。失敗時に通知する処理だけは必ず入れてください。依存が2段を超えた、ファイル到着が不定期になった、担当者が2人を超えた、のどれかが起きた時点がオーケストレーターへ移る目安です。cronから呼ぶ取込・変換・配信のスクリプトの組み方は[データパイプライン構築の手順](https://www.issoh.co.jp/tech/details/19627/)で解説しています。

### Dagster・Step Functionsを選ぶ条件と外部に任せる範囲の線引き

オーケストレーターを入れるとして、Airflowが常に正解ではありません。テーブル単位の依存と品質チェックを中心に管理したいなら[Dagster](https://www.issoh.co.jp/tech/details/15948/)が、処理がAWSのLambdaやECSタスクで完結するなら[AWS Step Functions](https://www.issoh.co.jp/tech/details/15429/)が、サーバの保守を減らせます。Pythonの関数をそのままフローにしたい小規模チームには[Prefect](https://www.issoh.co.jp/tech/details/10836/)も候補です。Airflowを選ぶのは、既存のDAG資産がある場合と、接続先が多くproviderの数が効く場合です。

外部に任せる範囲は、オーケストレーターの基盤構築と、本記事のような起動方式の設計までにします。どのテーブルをどの鮮度で更新するかという業務側の判断は、社内に残してください。既存のcronやスクリプトの棚卸しから自動化の範囲を決めたい場合は、[データ分析基盤構築・MLOps構築支援](https://www.issoh.co.jp/service/ai/data-platform/)で相談を受け付けています。

## データパイプライン自動化の実装でよくある質問と起動方式・ツール選びの判断

データパイプラインの自動化を進めるときに出やすい質問に答えます。

### データパイプラインの自動化とオーケストレーションは何が違いますか？

自動化は「人が手でやっていた作業を機械に任せること」全般を指し、オーケストレーションはそのうち複数の処理の順序・依存・再実行を管理する部分です。cronで1本のスクリプトを定時実行するのは自動化ですが、オーケストレーションとは呼びません。本記事のAsset起動やリトライはオーケストレーションの機能、dbtのCIはその外側の自動化です。概念の違いは[オーケストレーションとは](https://www.issoh.co.jp/tech/details/13632/)で詳しく扱っています。

### Airflow 2系の環境でもAssetやイベント起動は使えますか？

Airflow 2系では、同じ仕組みが「Dataset」という名前で2.4から提供されており、`outlets`と`schedule`によるデータ起動は書けます。3系でAssetへ改名され、importも`airflow.sdk`に移りました。一方、AssetWatcherとMessageQueueTriggerによるイベント起動は3.0で追加された機能で、2系では使えません。S3のファイル到着で起動したい場合は、3系へ移行するか、LambdaからAirflowのREST APIを呼んでDAGを起動する構成で代替します。

### ファイル到着の検知はセンサーとイベント起動のどちらを使うべきですか？

到着時刻がおおむね決まっていて、待つのが数十分程度ならセンサーでも足ります。到着が不定期で、1日中待つ可能性があるならイベント起動を選んでください。センサーは待っている間もタスクとして枠を使い続け、待ち時間の上限を決める必要があります。イベント起動はメッセージが届くまでDAG自体が起動しないため、待ち時間の設計が要りません。ただし本記事のとおり、二重に届く前提の冪等な取り込みが条件です。

### dbtのCIで本番のmanifestが無い初回はどうすればよいですか？

初回は`--state`を付けずに`dbt build`で全モデルをCI用スキーマに作り、同時に本番ジョブの最後でmanifestを保存する設定を入れます。2回目以降は保存したmanifestと比較できるようになります。manifestの保存先は、本番ジョブだけが書き込めて、CIは読み取りだけできる権限に分けてください。CIが本番の比較元を書き換えると、変更の検出が狂います。

### 自動化したあとに失敗に気づけない状態をどう防げばよいですか？

自動化で人が見なくなるぶん、異常を知らせる仕組みが要ります。最低限、タスクの最終失敗をチャットへ通知し、取り込みテーブルの鮮度を検査してください。リトライで回復した失敗も日次でまとめて確認すると、接続先の劣化に早く気づけます。Airflowの失敗通知とdbtの鮮度・件数・スキーマの検知をコード付きでまとめた手順は、[データパイプライン監視の実装](https://www.issoh.co.jp/tech/details/19623/)を参照してください。

## 関連記事

- [データパイプラインとは？種類・構成要素と冪等性から考える設計判断を解説【2026年版】](https://www.issoh.co.jp/tech/details/15848/)：自動化の前提となるパイプラインの設計
- [データパイプライン監視の実装：鮮度・件数・スキーマ変化をdbtとAirflowで検知する手順【2026年版】](https://www.issoh.co.jp/tech/details/19623/)：自動化したパイプラインの異常を検知する実装
- [データパイプラインの事例12選｜製造・病院・製薬・小売・通信の構成と遅延を比較【2026年版】](https://www.issoh.co.jp/column/details/18820/)：業種別の構成と自動化の判断材料
- [Apache Airflowとは？Jenkinsとの違い・DAGの書き方と3.3の導入手順](https://www.issoh.co.jp/tech/details/1441/)：本記事のDAGを動かすための基本
- [dbt Coreの使い方：インストールからprofiles.yml・dbt build・CIまでの手順【1.12対応】](https://www.issoh.co.jp/tech/details/19592/)：CIで動かすdbtプロジェクトの作り方

---

出典: [データパイプライン自動化の実装：Airflowのアセット起動・イベント駆動とdbtのCIで手作業をなくす手順【2026年版】](<https://www.issoh.co.jp/tech/details/19625/>)（株式会社一創）
