Files
windmill_workflow/docs/20_マスタードキュメント_Windmill通知ワークフロー編.md
2026-04-04 09:15:09 +09:00

14 KiB
Raw Permalink Blame History

マスタードキュメント - Windmill通知ワークフロー編

最終更新: 2026-02-21 対象システム: windmill.keinafarm.netワークスペース: admins 目的: このドキュメントだけでWindmill通知ワークフローの全容を把握できること


目次

  1. 機能概要
  2. フロー設計
  3. 変更履歴取得API仕様
  4. LINE通知仕様
  5. Windmill設定仕様
  6. 状態管理仕様
  7. 設計判断と制約
  8. 運用手順
  9. ソースファイル索引
  10. 更新履歴

1. 機能概要

目的

shiraou.keinafarm.net(白皇集落営農組合 統合システムで発生した予約・実績の変更を、LINE Messaging API 経由で管理者に通知する。

ユーザーフロー

統合システム上で予約・実績の変更が発生
  └→ Windmill が5分毎にポーリング
        └→ 変更があればLINEにプッシュ通知
              └→ 管理者がLINEで変更内容を確認

通知される操作一覧

区分 操作 説明
予約 create 予約が作成された
予約 update 予約の日時・機械が変更された
予約 cancel 予約がキャンセルされた
実績 create 実績が登録された
実績 update 実績が修正された
実績 delete 実績が削除された

2. フロー設計

Windmillフロー情報

項目
パス f/shiraou/shiraou_notification
概要 白皇集落営農 変更通知
ステップ数 1単一Pythonスクリプト
スケジュール 0 */5 * * * *5分毎、JST
スケジュールパス f/shiraou/shiraou_notification_every_5min

実行フロー(擬似コード)

# Step 1: シークレット・前回実行時刻を取得
api_key        = get_variable("u/admin/NOTIFICATION_API_KEY")
line_token     = get_variable("u/admin/LINE_CHANNEL_ACCESS_TOKEN")
line_to        = get_variable("u/admin/LINE_TO")
last_checked   = get_variable("u/admin/SHIRAOU_LAST_CHECKED_AT")  # 空なら初回

since = last_checked or (now() - 10)

# Step 2: 変更履歴を取得
response = GET "https://shiraou.keinafarm.net/reservations/api/changes/?since={since}"
  headers: { "X-API-Key": api_key }

# Step 3: 変更があればLINE通知
if response.reservations or response.usages:
    message = format_message(response)
    POST "https://api.line.me/v2/bot/message/push"
      body: { "to": line_to, "messages": [{"type": "text", "text": message}] }

# Step 4: 前回実行時刻を更新(正常完了時のみ)
set_variable("u/admin/SHIRAOU_LAST_CHECKED_AT", response.checked_at)

エラー時の挙動

  • API呼び出し失敗、LINE送信失敗のいずれでも例外が発生
  • 例外が発生した場合、SHIRAOU_LAST_CHECKED_AT は更新されない
  • 次回実行時に同じ since で再試行される(変更の取り漏れ防止)

3. 変更履歴取得API仕様

エンドポイント

GET https://shiraou.keinafarm.net/reservations/api/changes/

認証

X-API-Key: <NOTIFICATION_API_KEY>

APIキーが不正な場合は 401 Unauthorized が返る。

クエリパラメータ

パラメータ 必須 説明
since ISO8601文字列 必須 この日時以降の変更を取得する

since の形式例:

  • 2026-02-21T10:00:00+09:00(タイムゾーン付き、推奨)
  • 2026-02-21T10:00:00ナイーブ、JSTとして扱われる

レスポンス200 OK

{
  "checked_at": "2026-02-21T12:00:00+09:00",
  "since": "2026-02-21T10:00:00+09:00",
  "reservations": [
    {
      "operation": "create",
      "reservation_id": 123,
      "user_name": "田中太郎",
      "machine_name": "トラクター",
      "start_at": "2026-02-25T09:00:00+09:00",
      "end_at": "2026-02-25T12:00:00+09:00",
      "operated_at": "2026-02-21T11:30:00+09:00",
      "operator_name": "田中太郎",
      "reason": ""
    }
  ],
  "usages": [
    {
      "operation": "update",
      "usage_id": 456,
      "user_name": "山田次郎",
      "machine_name": "コンバイン",
      "amount": 4.0,
      "unit": "時間",
      "start_at": "2026-02-20T08:00:00+09:00",
      "end_at": "2026-02-20T12:00:00+09:00",
      "operated_at": "2026-02-21T11:55:00+09:00",
      "operator_name": "管理者A",
      "reason": "記録ミスのため修正"
    }
  ]
}

変更なし時のレスポンス

{
  "checked_at": "2026-02-21T12:05:00+09:00",
  "since": "2026-02-21T12:00:00+09:00",
  "reservations": [],
  "usages": []
}

エラーレスポンス

ステータス 原因
401 Unauthorized APIキーが不正または未設定
400 Bad Request since パラメータが欠落または不正な日時形式

4. LINE通知仕様

使用API

LINE Messaging API - Push Message

POST https://api.line.me/v2/bot/message/push
Authorization: Bearer <LINE_CHANNEL_ACCESS_TOKEN>
Content-Type: application/json

リクエストボディ

{
  "to": "<LINE_TO>",
  "messages": [
    {
      "type": "text",
      "text": "<フォーマット済みメッセージ>"
    }
  ]
}

メッセージフォーマット

📋 営農システム 変更通知

🟢 予約作成
  機械: トラクター
  利用者: 田中太郎
  日時: 2026-02-25 09:00 〜 2026-02-25 12:00

🔴 予約キャンセル
  機械: 田植機
  利用者: 佐藤花子
  日時: 2026-02-22 08:00 〜 2026-02-22 17:00

🔵 実績修正
  機械: コンバイン
  利用者: 山田次郎
  利用量: 4.0時間
  日: 2026-02-20
  理由: 記録ミスのため修正

アイコン規則

アイコン 意味
🟢 作成create / 予約作成 / 実績登録)
🔵 変更update / 予約変更 / 実績修正)
🔴 削除・キャンセルcancel / delete

通知先の種別

LINE_TO にはユーザーIDまたはグループIDを設定する。

種別 ID形式
ユーザー U で始まる文字列
グループ C で始まる文字列

5. Windmill設定仕様

Windmill Variablesシークレット

以下の変数を Windmill UIVariables ページ)で作成・管理する。

変数パス Secret 説明 取得元
u/admin/NOTIFICATION_API_KEY shiraou.keinafarm.net のAPIキー Djangoサーバー側 NOTIFICATION_API_KEY 環境変数と同一値
u/admin/LINE_CHANNEL_ACCESS_TOKEN LINE Messaging API チャネルアクセストークン LINE Developers Console
u/admin/LINE_TO 通知先のLINEユーザーIDまたはグループID LINE webhook / profile API
u/admin/SHIRAOU_LAST_CHECKED_AT 前回確認時刻(ワークフローが自動更新) ワークフローが自動管理(初期値: 空文字)

Django側の設定shiraou.keinafarm.net

docker-compose.yml に以下の環境変数を追加:

environment:
  - NOTIFICATION_API_KEY=<NOTIFICATION_API_KEYと同一の値>

APIキー生成コマンド:

openssl rand -hex 32

6. 状態管理仕様

状態変数: SHIRAOU_LAST_CHECKED_AT

項目 内容
格納場所 Windmill Variable u/admin/SHIRAOU_LAST_CHECKED_AT
ISO8601文字列例: 2026-02-21T15:30:00+09:00
初期値 空文字(初回実行時は 現在時刻 - 10分 を使用)
更新タイミング フロー正常完了時のみ、APIレスポンスの checked_at を保存
参照タイミング フロー実行開始時、since パラメータとして使用

重複通知防止の仕組み

実行1: since=T0, checked_at=T1 → LAST_CHECKED_AT = T1
実行2: since=T1, checked_at=T2 → T1以降の変更のみ取得
  • sincechecked_atAPIが確認した時刻を使うことで、変更の取りこぼしが発生しない
  • since(リクエストに渡した時刻)ではなく checked_at(サーバーが確認した時刻)を保存するのがポイント

旧実装との違い(トラブルシュート記録)

旧実装 現実装
状態保存方法 wmill.get_state() / set_state() wmill.get_variable() / set_variable()
問題 フローのインラインスクリプトでは実行をまたいで保存されない -
症状 毎回 since = 現在 - 10分 になり、毎回通知が飛ぶ 正常動作

7. 設計判断と制約

絶対に変えてはいけない制約

  1. SHIRAOU_LAST_CHECKED_AT には checked_at を保存することsince を保存しない)

    • checked_at: APIサーバーが「この時刻まで確認した」という保証付きの時刻
    • 同じ変更が2度通知されることを防ぐ
  2. 状態更新は正常完了後のみ行うこと

    • API呼び出し失敗・LINE送信失敗時は SHIRAOU_LAST_CHECKED_AT を更新しない
    • 次回実行で同じ範囲を再取得し、通知の取り漏れを防ぐ
  3. wmill.get_state() は使用しないこと

    • Windmillのインラインフロースクリプトでは実行をまたいで保存されない
    • 状態管理は必ず Windmill Variable を使うこと

設計判断

判断 理由
単一ステップフロー 状態管理を1か所に集約するため。get_state()/set_state() のスコープ問題を回避
SSL検証スキップ shiraou.keinafarm.net が自己署名証明書の可能性があるため
タイムアウト 30秒 農業用途で多少の応答遅延を許容しつつ、無限待機を防ぐ
5分ポーリング間隔 農業機械の予約用途では数分の遅延は許容範囲。リアルタイム不要

8. 運用手順

フローを手動実行

curl -sk -X POST \
  -H "Authorization: Bearer qLJ3VPZ61kTDiIwaUPUu1dXszGrsN1Dh" \
  -H "Content-Type: application/json" \
  -d '{}' \
  "https://windmill.keinafarm.net/api/w/admins/jobs/run/f/f/shiraou/shiraou_notification"

動作確認curlで直接API呼び出し

# 変更なし確認
curl -H "X-API-Key: <キー>" \
  "https://shiraou.keinafarm.net/reservations/api/changes/?since=2026-02-21T11:59:00%2B09:00"

# 広い範囲で変更取得(初期確認用)
curl -H "X-API-Key: <キー>" \
  "https://shiraou.keinafarm.net/reservations/api/changes/?since=2026-01-01T00:00:00"

フローの更新デプロイ手順

cd /path/to/windmill_workflow

# 1. flows/shiraou_notification.flow.json を編集

# 2. 既存フローを削除して再作成PUTは405のため
curl -sk -X DELETE \
  -H "Authorization: Bearer qLJ3VPZ61kTDiIwaUPUu1dXszGrsN1Dh" \
  "https://windmill.keinafarm.net/api/w/admins/flows/delete/f/shiraou/shiraou_notification"

curl -sk -X POST \
  -H "Authorization: Bearer qLJ3VPZ61kTDiIwaUPUu1dXszGrsN1Dh" \
  -H "Content-Type: application/json" \
  -d @flows/shiraou_notification.flow.json \
  "https://windmill.keinafarm.net/api/w/admins/flows/create"

# 3. スケジュールは再作成不要(フローの削除・再作成でも維持される)

APIキーローテーション手順

  1. Djangoサーバー側で新しいキーを生成: openssl rand -hex 32
  2. docker-compose.ymlNOTIFICATION_API_KEY を更新してデプロイ
  3. Windmill UI で u/admin/NOTIFICATION_API_KEY の値を同じ新しいキーに更新
  4. フローを手動実行して動作確認

過去のジョブ結果確認

curl -sk -H "Authorization: Bearer qLJ3VPZ61kTDiIwaUPUu1dXszGrsN1Dh" \
  "https://windmill.keinafarm.net/api/w/admins/jobs/list?per_page=10&script_path_exact=f/shiraou/shiraou_notification&is_flow=true"

9. ソースファイル索引

フロー定義

ファイル 説明
flows/shiraou_notification.flow.json フロー本体。単一Pythonステップでポーリング・通知・状態更新を実行

フロー構造:

{
  "path": "f/shiraou/shiraou_notification",
  "value": {
    "modules": [
      {
        "id": "a",
        "value": {
          "type": "rawscript",
          "language": "python3",
          "content": "..."
        }
      }
    ]
  }
}

ヘルパースクリプト

ファイル 説明
wm-api.sh Windmill REST API操作ヘルパー。フロー作成・スケジュール管理に使用

主要コマンド:

create-flow <file>          JSONファイルからフローを作成
create-schedule <file>      JSONファイルからスケジュールを作成
flows                        フロー一覧取得
schedules                    スケジュール一覧取得

ドキュメント

ファイル 説明
docs/shiraou/19_windmill_通知ワークフロー連携仕様.md 仕様書。API仕様・メッセージフォーマットの原典
docs/shiraou/20_マスタードキュメント_Windmill通知ワークフロー編.md 本ドキュメント

エージェントワークフロー

ファイル 説明
.agent/workflows/windmill-push.md Windmillへのpush手順。wmill CLIの制限とAPI代替の経緯を記録
.agent/workflows/windmill-new-script.md 新規スクリプト作成手順

更新履歴

日付 変更内容
2026-02-21 初版作成。フロー登録・スケジュール設定・状態管理バグ修正を含む