こんにちは、ヤプリで iOS エンジニアをしている三宅 (@tsushi130) です。
これまで SaaS を利用していた受付アプリを内製化した iPad アプリに移行する方針となり、その API を Cloud Run × Swift を利用して実装しました。
背景
2020 年にリモートワークの社員が増加しつつ来客数も減少している中で、年間 100 万円以上もかかっていた受付アプリのコストを削減すべく、内製化した受付アプリのリリースに向けて動き出したことが背景です。
技術選定
社内アプリということとアプリチーム主導で進めるということで、触れてみたい技術や新しい技術を取り入れつつ、新技術の検証題材としても活用していきたいという意図がありました。
また、iOS チームで運用している周辺システムの開発言語が Swift / Objective-C / Node.js / Typescript / Ruby / PHP・・・など様々で、言語スイッチが多いというところもシューティングしたいという観点から、サーバーサイドを Swift で書くに至りました。(割とノリと勢いなところもあります😂)
要件
来客者が受付アプリで受付を済ませると、呼び出す担当者を Slack の受付用チャンネルでメンション付きで通知したい。かつ1分ごとにスレッドに再通知を行い OK ボタンを押すまで呼び続けたいとのことでした。
また、呼び出す社員の情報をこれまで手動で追加する必要がありましたが、Google Workspace で社員を追加したら自動で反映されてほしいという要望も頂いていました。
アプリイメージ
利用した API
社員情報取得に Google Admin SDK の Directory API、Slack 通知に Slack API を利用しました。
構成
API を Swift で実装するために、Docker イメージを Cloud Run へデプロイすることで実現していきます。
サーバーサイド Swift のフレームワークには Vapor を利用しました。Vapor のコマンドでプロジェクトを作成していくと Dockerfile も自動生成してくれるため、基本的なベースは簡単に整えられます。認証部分やエラー通知など Middleware を使うことで簡単に仕組みを作れるのでスムーズに実装できました。
ビルドとデプロイには Cloud Build を Github と連携させて、master push をトリガーに本番環境へデプロイされるように設定を行いました。
実装で詰まったところ
Cloud Run 特有の問題
API のいくつかのエンドポイントで、レスポンスを返しながらも非同期に処理している実装がいくつかありました。ローカルで実装・動作検証を行う中では全く問題がなかったのですが、Cloud Run にデプロイすると非同期処理が動作しなくなる挙動を確認し、環境差分によるものとして調査を進めたところ、Cloud Run の CPU 割り当て方式の設定が原因でした。
CPU 割り当てには、「リクエストプロセス中のみ CPU を割り当てる」「常に CPU を割り当てる」の2種類選択でき、前者はレスポンスを返却後から CPU が割り当てられなくなる。もしくは強く制限されます。
前者の設定を行なっていたことで、非同期処理中にレスポンスが返却され、CPU の割り当てが解除されたことで動作しなくなっていたことが原因でした。Always on CPU を選択することでこの問題が修正されました。
この問題はサーバーサイド Swift でなくとも起きうる問題なので、非同期処理を扱う上では注意が必要そうです。
新しい CPU 割り当てコントロールにより Cloud Run 上でさらに多様なワークロードを実行 | Google Cloud 公式ブログ
実装面
実装面では特に詰まったところはなかったのですが、Google の Directory API をサービスアカウントで利用する Swift の実装はあまり参考になるものがなかったので、調査に少しだけ時間がかかりました。
サービスアカウントを利用した認証には google-auth-library-swift を利用したのですが、ライブラリで提供されている JWT Claim に Directory API で必要な subject の定義がなくそのまま利用できなさそうだったので、拡張する形で実装したりしました。(ご存じの方がいれば教えてください!)
利用頻度の高い言語ではないことからも 、ライブラリが提供されていない場合があるのはデメリットかもしれません。
最後に
普段はアプリメインで実装しているため、サーバーサイドに触れる機会は少なかったですが、サーバーサイドを Swift で実装する敷居もかなり下がり、Google Cloud Platform を活用することでかなり手軽に実現することができました。
また、アプリ - API 間でやりとりする JSON のための構造体も、Swift Package として切り出しておけばアプリと共有できるので、連携時の実装が楽になります。
運用しているアプリではサポート OS バージョンや開発環境の関係から、新しい技術を試すには敷居が高いこともあると思いますが、手触り感を検証するにもいい題材になりました。サーバーサイドの実装に挑戦してみたい iOS エンジニアも少しは試しやすくなったと思います。
ヤプリでは新しい技術や挑戦に対して快く背中を押してくれるので、色々なことを挑戦・改善したい方は是非ヤプリにも興味を持っていただけたらと思います!