はじめに
LINEの「リマインくん」を利用しているのですが通知が時間通りに来ないことがあり,困っていたので自作することにしました.
構成
今回はGoogleCoudへのデプロイを行いました.また,最近はFastAPIを利用する機会が多かったのでPythonで実装することにしました.
- FastAPI
- CloudRun
- Firestore
- CloudScheduler
- LINEmessagingAPI
LINEmessagingAPIについて
このAPIを通じてユーザへ公式アカウントからのアクションを実行できます.
無料枠内ではユーザへのメッセージは200通/月が上限ですが,ユーザ主体のメッセージへの応答は対象外です.これを用いると予定の登録完了通知等は無料枠を消費することなく行えるため,6通/日程度のリマインド通知を無料枠内で行うことができます.
APIを実装する
FastAPIを用いて予定を管理するバックエンドを作成します.
messagingAPIはユーザからのアクションを任意のURLへPOSTします.このwebhookに含まれるjsonを得るためにpydanticを用います.
from pydantic import BaseModel
class BottomMessageModel(BaseModel):
text: str
class BottomSourceModel(BaseModel):
userId: str
class MidEventModel(BaseModel):
source: BottomSourceModel
replyToken: str
message: BottomMessageModel
class RootModel(BaseModel):
events: list[MidEventModel]
これでPOSTに含まれるjsonから応答メッセージの送信に必要な情報を拾うことができます.

さらに,POSTのヘッダーから認証情報を取得して検証をします.
次に送信された情報を分類します.
このリマインダーには予定の登録,確認,削除機能を実装します.
MM月DD日HHMM[予定の内容]で登録,一覧で登録している予定一覧の表示,削除[削除したい予定のインデックス]で削除としました.
次に予定の管理周辺を実装します.
今回はDBにNoSQLであるFirestoreを利用します.デプロイ先であるCloudRunと同じGoogleCloudサービスであり,認証周辺が整備されています.
Firestoreにはコレクションの中にフィールドを保有するドキュメントが存在します.
コレクションであるreminderについてuserId title timestampフィールドを持つドキュメントを追加します..addではドキュメント名は自動で生成されます.
最後に応答メッセージ用のペイロードを作成します.
replyTokenはwebhookのbody内に含まれます.また,channelTokenは公式アカウントを作成したときに発行されます.notificationDisabledはユーザへの通知の有無です.今回は処理完了メッセージの送信のため通知は無しにしています.
さらに,応答メッセージの送信はユーザのアクションから1分以内の動作のみ保証されているので,時間を要する処理は推奨外であることに注意してください.
応答トークンは一度のみ使用できます。
応答トークンは、Webhookを受信してから1分以内に使用する必要があります。1分を超える場合の使用については、動作は保証されません。
LINE Developers
さらにエンドポイントに/cronを追加して予定通知を実装します.
このエンドポイントにはCloudSchedulerが毎分アクセスして予定されているリマインドを確認します.
リマインドが存在しない場合にはリターンしてリソースを節約します.
リマインドの確認には現在時刻の30秒先から過去のリマインドについて存在確認をします.
これはCloudRunのコールドスタートによって現在時刻の取得が遅れた際にも実行されるようにするためです.
また,通知を送信する前にドキュメントを削除することで通知の再送を防ぎます.
CloudRunへのデプロイ
無料枠内での利用を目指すので極力インスタンスは少なくしてコールドスタートを許容します.
また,ビルドリソースを節約するために.gcloudignoreを作成しましょう.
.git
.gitignore
__pycache__/
app/__pycache__/
docker-compose.yml
gcloud run deploy --source . --region asia-northeast1 --min-instances 0 --max-instances 1 --memory 512Mi --allow-unauthenticated
叩かれない間はインスタンスを0にすることでリソースを節約することができます.
プロジェクトへの権限追加(Firestore,CloudScheduler)も忘れないようにしましょう.
CloudSchedulerへの登録
今回は毎分の予定チェックを行うので頻度は*****で登録します.
ターゲットタイプはHTTP,HTTPメソッドはPOSTにしました.
LINE Developersへの登録
アカウントを作成して公式アカウントを作成します.

チャネル内のMessaging API設定よりWebhookの登録をします.

検証が成功したら終了です.
コードをGitHubにて公開しているのでよろしければどうぞ
