前回の記事で「Apprise + 自作 Web サービスで OnCall 相当を組む」例を示しました。この記事ではよくある誤解を整理し、シフト管理を含めた自作 OnCall スタックの現実的な選択肢を深掘りします。
まずは Apprise の正しい位置付けを確認
Apprise は名前から「シフト管理ができそう」と誤解されがちですが、実際の役割は明確に分かれています。
正しい位置付け:
- Apprise は 「通知の超便利ハブ」 — 1 つのコードで Slack / メール / SMS / LINE / Telegram など 100 種類以上の通知先に統一インタフェースで送る
- シフト管理機能(カレンダー、ローテーション、当番判定)は持たない
- 「シフト管理に Apprise を使う」とは、シフトロジックは別のライブラリ / DB / カレンダーで持ち、通知配信だけ Apprise に任せるという意味
つまり Apprise は「組んだシフトを確実に届ける道具」であり、「シフトを組む道具」ではありません。前回記事のコード例で get_policy_for_now() を Python で書いていたのは、まさにこの「シフト判定ロジックを自作」の実装です。
シフト管理を「自作する場合」に組み合わせる Python ライブラリ
シフトロジックを自分で書くなら、以下のライブラリが Apprise と相性が良い。
1. PyShift(point85/PyShift) — 古典的なシフトローテ
point85/PyShift は、Java 版の Shift ライブラリを Python に移植したもの。PyPI では PyWorkShift として配布されています。
| |
Apprise との連携イメージ:
| |
工場・病院・ホテルなどの規則的なローテーションには強いが、IT のオンコールのように「毎週 1 人ずつ持ち回り」「祝日避けて再配置」といった柔軟性は弱め。
2. PuLP / Google OR-Tools — 最適化ベースのシフト生成
複雑な制約があるシフト割当(「夜勤明けの日勤禁止」「週 40 時間以内」「全員平等にカバー」)を最適化問題として解くライブラリ。
- PuLP — 線形計画法、シンプル
- Google OR-Tools — より高性能、CP-SAT ソルバ搭載
シフト表は 生成して DB / YAML に保存し、運用時はそれを読んで Apprise で通知、という構成が一般的。
| |
「シフト表を毎月自動生成 → DB に投入 → 運用中は Apprise で通知」が王道パターン。
3. Google Calendar + Python + Apprise(最も実用的)
実は最も手軽で広く使われているのはこの組み合わせ。「ガチガチのシフトソフト」より、Google Calendar を共有してそこで運用する方が圧倒的に現場で機能します。
「個別予定の共有」ではなく「1 つの共有カレンダー」が基本
よくある誤解として「担当者ごとに予定を作って共有するのか?」がありますが違います。「OnCall シフト」という 1 つの専用カレンダーを作り、シフトイベントを並べて、チーム全員に閲覧権限で共有するのが標準パターンです。
| |
| やり方 | 特徴 |
|---|---|
| ❌ 個別の予定を各担当者と共有 | 1 件ずつ招待を送る運用、シフト変更が面倒、全体像が見えない |
| ✅ 1 つの共有カレンダーに当番イベントを並べる | カレンダー全体を見れば全シフトが俯瞰、編集も 1 箇所 |
セットアップ手順
- 専用カレンダーを作成 —
Engineering OnCallなどの名前で、個人予定とは分離 - 権限を設定 — チーム全員は閲覧、シフト管理者のみ編集、API 連携用にサービスアカウントを読み取り権限で追加
- シフトイベントを作成 — タイトルや説明欄に担当者のメールアドレスを入れる
- 階層分けは「カレンダーを分ける」のが最も実装が楽 —
OnCall-Primary、OnCall-Secondaryの 2 つに分けると API も読みやすい
「今の当番」を取得する Python コード
| |
メリット
- 担当者がカレンダーを「自分の予定」として確認できる — 「来週は当番だ」を Calendar アプリが通知してくれる
- シフト変更がドラッグ&ドロップ — 「来週入院するから誰か変わって」を 30 秒で対応
- 休暇・代理対応もカレンダーで普通に編集
- 過去ログが残る — 「あのインシデント時の当番は誰だったか」が後から正確にわかる
- モバイルで全員が見られる — Calendar アプリを入れればすぐ
- API 連携が簡単 — Google 公式
- 追加コストゼロ — Workspace に既に含まれている
落とし穴
- タイトルから担当者を抽出するのは脆弱 — 表記ゆれで失敗する。説明欄や
attendeesフィールドに正規化して入れるか、Extended Properties を使うと堅牢 - タイムゾーンの扱い — UTC と JST が混ざるので API では明示的に指定(
datetime.now(timezone.utc)) - 「終日」イベントは避ける — 時刻判定が曖昧になるので必ず時刻付きイベント
- シフト境界の瞬間 — 月曜 09:00:00 ぴったりは前後どちらか、
timeMin = now - 1秒などで安全側に倒す - 「今の」イベントが複数返る — 階層別カレンダーで分けるか、優先度ルールを決める
代理対応のパターン
「田中さんが来週休みなので佐藤さんに代わる」場合:
- カレンダーで田中のイベントを佐藤に書き換える — 最も簡単
- 田中のイベントを「OOO」に変更し、佐藤の代理イベントを追加 — 履歴を残したい場合
OnCall-Override専用カレンダーを別に持つ — そちらに該当者がいればそちらを優先
「予定をひとりずつに送る」のではなく、**「全員が見られる単一のシフト表 = カレンダー」**がポイントです。
4. Microsoft 365 / Teams 環境で同じ運用を行う
「Google Calendar 運用」を Microsoft 365 / Teams 環境でやりたい場合、完全に同じパターンが成立します。コンポーネントを差し替えるだけで思想は同じです。
コンポーネントの対応関係
| 役割 | Google Workspace | Microsoft 365 / Teams |
|---|---|---|
| シフト表 | Google Calendar 共有カレンダー | Outlook/Exchange 共有カレンダー |
| API | Google Calendar API | Microsoft Graph API(統一 API) |
| 認証 | サービスアカウント | Azure AD アプリ登録 + クライアント資格情報フロー(msal) |
| チャット通知 | Google Chat / Slack | Teams Incoming Webhook |
| 専用シフト管理アプリ | — | Microsoft Shifts(Teams 内蔵、別パターン) |
パターン A: Outlook 共有カレンダー(最も直接的な移植)
Google Calendar 版とほぼ同じ構造。
セットアップ:
- Outlook で「Engineering OnCall」共有カレンダーを作成 — Microsoft 365 グループに紐付けるのが一般的
- チームに閲覧権限で共有
- Azure AD でアプリ登録 —
Calendars.Read.SharedまたはCalendars.Readの Application permission を付与 - 管理者同意(admin consent) を取得 — テナント全体への読み取り権限
Microsoft Graph API での実装:
| |
パターン B: Microsoft Shifts(Teams 内蔵のシフト管理)
Teams には Shifts というシフト管理専用アプリが標準で組み込まれています。
特徴:
- Teams の左サイドバーに常駐 — 担当者は Teams を開くたびに自分のシフトが見える
- シフト交換・申請・承認のワークフロー内蔵
- タイムクロック機能(出退勤打刻)
- Power Automate 連携可能
- Microsoft Graph API(
/teams/{id}/schedule) でシフトデータ取得可能
| |
要求権限: Schedule.Read.All(管理者同意必要)
A vs B の使い分け
| 用途 | Outlook 共有カレンダー(A) | Microsoft Shifts(B) |
|---|---|---|
| シフト表の編集 UI | カレンダーアプリ | 専用 UI(直感的) |
| シフト交換ワークフロー | なし(手動編集) | あり(依頼・承認) |
| タイムクロック | なし | あり |
| API の単純さ | 簡単(Calendar API) | やや複雑(Schedule API) |
| 適合用途 | IT オンコール、軽量運用 | フロントライン勤務(小売・医療等) |
IT のオンコール用途なら Outlook 共有カレンダー(A)で十分。交代制勤務の本格運用なら Shifts(B)。
Apprise の Teams 通知連携
| |
Teams チャネルの設定で Incoming Webhook コネクタを有効化し、生成された URL の token 部分を Apprise URL に変換するだけ。
⚠️ 注意: Microsoft は Connector ベースの Incoming Webhook を Power Automate Workflow に段階的に移行しています。最新環境では Workflow 用 Webhook を使う必要がある場合あり。Apprise 側も
msteamswrapperプラグインで対応中。
Azure AD アプリ登録時の落とし穴
- Application permission を選ぶ(Delegated ではない) — サービスとして動かすため
- 必要スコープ:
Calendars.Read.Shared(A)orSchedule.Read.All(B) - 管理者同意(admin consent)が必須 — テナント管理者にお願いして承認
- Client secret は Azure Key Vault などで管理、コード直書きは厳禁
- タイムゾーンは
Prefer: outlook.timezone="Tokyo Standard Time"ヘッダで指定可能 - Microsoft Graph はレート制限が厳しめ —
429 Too Many Requestsのリトライ実装必須
選択指針
| 状況 | 推奨 |
|---|---|
| Google Workspace 中心 | Google Calendar + Calendar API + Apprise |
| Microsoft 365 / Teams 中心 | Outlook 共有カレンダー + Graph API + Apprise(msteams 通知) |
| シフト交換ワークフローも本格運用したい | Microsoft Shifts + Graph API + Apprise |
| シフト管理 UI を Teams に統合したい | Channel Calendar アプリ(バックエンドは Outlook と同じ)+ Graph API |
エンタープライズで M365 を既に契約している場合、追加コストゼロでこの構成が組めるのが大きな利点です。
シフト管理 + 通知が「最初から統合された」OSS
「自作ではなく既製品で」という選択肢:
GoAlert(Target 社 OSS)— OnCall OSS アーカイブ後の有力代替
GoAlert(Apache 2.0)は、Target 社が OSS 公開しているオンコール管理ツール。Grafana OnCall OSS のアーカイブを受けて注目度が急上昇しています。
機能:
- ブラウザ UI でドラッグ&ドロップのシフト編集
- エスカレーションポリシー(一定時間応答なしで次の人へ)
- ローテーション + Override(一時的な交代)
- API + GraphQL での連携
通知手段:
- Twilio で SMS / 音声通話(唯一サポートされているプロバイダ)
- SMTP でメール
- Slack チャンネル統合
GoAlert は Twilio + SMTP + Slack を直接統合する設計で、Apprise は使っていません。Apprise の 100 種類超の通知先を活かしたい場合は、別途自作ハブを挟むか、Apprise の Webhook を GoAlert の通知ターゲットに据える形になります。
GoAlert の標準範囲で足りる組織なら、自作よりずっと楽。
その他の OSS
- Alerta — アラート集約 + ack / シェルブ機能、シフト管理は弱い
- OneUptime — オンコール + インシデント + ステータスページの全部入り OSS
- Karma — Alertmanager 専用 UI、通知ではなく可視化
自作スタックの完成形
前回記事の Apprise + FastAPI 自作サービスに、シフト管理を組み込んだ完成形:
| |
実装の最小増分:
| |
これで「カレンダーで誰でも編集できるシフト表 + Apprise の通知柔軟性 + 自作の細かい制御」を全部手に入れられます。
規模別の推奨構成(再整理)
| 規模 | 推奨構成 |
|---|---|
| 個人 / 1〜3 人体制 | 自作 FastAPI + Apprise + Google Calendar(シフト表として) |
| 5〜10 人、IT オンコール中心 | GoAlert + Twilio + Slack(自前運用が前提) |
| 5〜10 人、シフト規則が複雑 | OR-Tools でシフト生成 + 自作 + Apprise |
| 10 人超、24/7 + 音声通話必須 | Zenduty / OnPage / PagerDuty SaaS |
| エンタープライズ + Grafana スタック | Grafana Cloud IRM |
Apprise はシフト管理しないこと、Grafana OnCall や GoAlert は Apprise ではなく独自の通知統合で動いていることを理解した上で、自分の環境に合うレイヤーを選ぶのが正解です。
まとめ
- Apprise = 通知ハブ。シフト管理機能はない
- シフト管理を自作するなら: PyShift(規則的)、OR-Tools(最適化)、Google Calendar / Outlook 共有カレンダー(実用最強)
- 既製品で済ませるなら: GoAlert(OSS)、または有料 SaaS(Zenduty / IRM / PagerDuty)
- Microsoft 365 環境なら Outlook 共有カレンダー + Graph API で同じ思想がそのまま動く
OnCall OSS 後の OSS 自作の現実解として、Apprise + 共有カレンダー + 自作 Web サービスが最もシンプルかつ実用的、というのが筆者の結論です。