Push 通知送信エージェント Gunfish に FCM v1 API 対応を追加した

SREチームの藤原です。Tech Kayac Advent Calendar Migration Track 17日目の記事です。

Gunfish?

カヤックでは iOS (APNs) や Android (FCM、かつては GCM) へのモバイルプッシュ通知に、自社で開発した Gunfish というソフトウェアを使用しているプロジェクトが多くあります。

APNs にはクライアント認証のための証明書を用意した上で HTTP2 で接続する必要があるのですが、Perl などの LL で開発されているプロジェクトで個々に HTTP2 で接続するのは難しい時代がありました。またレイテンシ的にも同期でプッシュ通知を送信すると性能への影響が大きいため、一旦 Proxy 的にバッファリングをしてくれるソフトウェアを間に挟んで、アプリケーションからはそこへ認証なしで HTTP1 で送信する形を取るために生まれたものです。そのあたりの経緯は以下の記事にまとまっています。

techblog.kayac.com

さて、そうなると iOS 向けの APNs だけではなく Android 向けの GCM や FCM もそこでまとめて扱いたい、という自然な要求が生まれ、v0.2.0 で FCM への送信機能が追加されました。

FCM v1 API の要望

最近カヤックでは、北欧、暮らしの道具店 を運営している株式会社クラシコムさんのお手伝いをしています。SRE チームでもモバイルアプリのリリースに伴ってプッシュ通知基盤を整備したり、既存の EC2 で動作しているシステムを整理して Amazon ECS のコンテナ環境へ移行するお手伝いをしています。

techblog.kayac.com

今回は iOS アプリに対しても FCM を利用してプッシュ通知を行うとのことだったため、Gunfish を ECS サービスとしてデプロイしたところ、「通知に画像を入れたい」という要望が寄せられました。FCM には現在レガシー API と v1 API があり、画像を入れられるのは v1 API のみなのですが、Gunfish ではこれまでレガシー API にしか対応していなかったのです。

FCM v1 API の存在自体は認知していたもののの 以前の HTTP から HTTP v1 に移行する を読むと

注意: デバイス グループ メッセージングを使用するアプリは、アップグレードしないことをおすすめします。HTTP v1 では、従来の FCM API のこの機能がサポートされないためです。

と書いてあり、使えない機能もあるし、今困ってないなら無理に移行することもないよね…という消極的な姿勢でいたためです。

しかし必要とあれば仕方ない、やりましょう、ということで新しく /push/fcm/v1 というエンドポイントを用意して対応を行いました。以前に FCM レガシー API に対応した時点で、リファクタリングと適切な抽象化が行われていた結果、FCM v1 の追加は比較的容易に、数時間程度の実装で完了しました。リファクタリングは身を助く、よかったですね。

バルク送信への対応

さて、v0.4.0 で FCM v1 API 対応をしてこれでめでたしめでたし…かと思いきや、FCM レガシー API から v1 APIへの移行にはひとつ問題がありました。

レガシー API では payload の "registration_ids" というキーに、複数のデバイスのトークンを送信することでバルク送信できるという機能があったのですが、この機能は v1 API にはありません。つまり API 的には1件ずつしか送れない、不便ですね。

ドキュメントの 複数のデバイスにメッセージを送信する には

  • トピック メッセージング を使う
  • デバイス グループ メッセージング を使う

という方法しか書いてありません。先述の通り、デバイスグループメッセージングは v1 API では利用不可です。ということで、頑張って複数回叩いて送るしかないですかねーという話をしたのですが、Firebase admin SDK を確認した人から、SendMulticast というメソッド があるので、これは使えないかと。

API 的にはそんな機能はないはずなのでおかしいなと実装を読んでみたところ、なんと HTTP Body に multipart で複数の payload を並べて送信することで、1回の HTTP リクエストで複数のデバイスへの送信ができるみたいですね。APIドキュメントにはそんなこと書いてないのに…

ということで、今日からバルク送信への対応をはじめたところです。年内にはリリースしてすっきり年を越したいところですね!