Jicooのアーキテクチャと技術スタック
エンジニアリング

Jicooのアーキテクチャと技術スタック

2022年10月24日(月)
Haruhiko Kobayashi

こんにちは、Jicoo CTOの小林です。

Jicooは毎日の仕事においての日程調整や予約受付に関連する業務や作業を自動化し、調整業務を行う時間を減らし本来行うべき価値ある時間を生み出す事を推進するためのサービスです。

2022年7月現在のJicooがどう作られているかに興味を持ってもらうために、ブログとして技術情報を発信していく事にしました。最初の記事として利用している技術やサービスを紹介し、その後は日程調整や予約のトピックを深掘りした情報を書いていきたいと思います。

というわけで今回の記事は、Jicooを支えるアーキテクチャと技術スタックを紹介します。

アーキテクチャ全体像

JicooはインフラとしてGCPを採用しており、大まかな全体像は下記の図のようになっています。フルマネージドなサーバレスプラットフォームであるCloud Runを中心にしたシステムになっています。 システムアーキテクチャ全体像

コンセプト

全ての処理はCloud Runに集約

APIはユーザー、Cloud Scheduler、Cloud Tasksそして外部サービスのwebhookがコールをしてきますが、全ての処理をCloud Runで実行するようにすることでデータフローが一元化されシンプルになります。

今後サービスが拡大するに伴いHTTP以外で処理を行う必要も出てくると思いますが現状はこれで間に合っているのと管理コストがほぼかからないのでとても楽です。

共通言語: TypeScript

全てのコードがTypeScriptベースになっているのが特徴です。(一部iOSアプリでSwiftを利用しています)

TypeScriptが書けるエンジニアならFE、BE、Macアプリ(Electron)、iOSアプリそしてAndroidアプリ(PWA)の全てが修正出来るようになっており、高速に開発ができ、フロントエンドエンジニアがBEの開発を行うといった越境開発がしやすい環境を目指しています。


各領域を支える技術

App(SSR)

リクエストを受けるインスタンスはNext.jsのSSR機能を利用している昨今では割と一般的な構成になっています。インフラはCloud Runを利用しておりサーバレスになっていて運用負荷はほぼゼロです。アクセスの少ない深夜はスケールインして日中はスケールアウトを自動で行なってくれるのでコストも最適化してくれます。

元々はGAE flexibleを利用していたのですが、最低でも1インスタンスは稼働する必要があるためsandbox環境のインフラコストが課題になっていました。Cloud Runを採用した昨年の11月以降は開発環境未使用時は0インスタンスになり課金されない運用が可能になったためsandbox環境のコストが50%近く削減できました。

App(API)

APIの利用者が不特性多数になるサービスではないため、GraphQLではなくRESTを採用しています。 Next.jsのAPI Routesに各種APIを定義しています。

APIの型はinterfaceを定義して、BEとFE両方で参照できるようになっています。

FE

WebアプリのフレームワークはNext.jsを利用しているためReactを採用し、Atomic Designをベースにしてコンポーネントを分割・管理しています。 CSSの定義はEmotionを採用しており、エンジニア・デザイナー誰でも変更ができるようになっています。

MacアプリはElectronとwebview、iOSアプリはSwiftとwebviewのハイブリッドで実装。 AndroidアプリはPWAで実装しているため基本はwebと同じコードとなっています。 提供デバイスは多種多様ながらもコードベースはほぼ1つで全てを賄う事ができているのでマルチデバイス開発の対応スピードが早いのが特徴です。

Batch

バルクメール等を配信したりするバッチ処理を行うインスタンスです。Cloud Schedulerにcron形式で実行時間を定義して実行自体はCloud Runが受けるようになっています。

現状特に不満はないのですがCloud Run JobsがGAになったら移行予定です。

Job Queue

メール送信やZoomURL作成等のコストのかかる外部APIの実行はAPIのオンライントランザクション処理では実行せずにJob Queueに作業をオフロードしてレスポンスを速く返すようにしています。Cloud Tasksを採用しています。

こちらも実行はCloud Runのエンドポイントを叩きます。1つのjobはなるべく小さな処理のみにしておきretryが発生してもデータに不整合が起きないようにしています。

元々はRedisで動くnpmのbullというpackageでJob Queueを運用していたのですが、デフォルトではジョブ管理画面がなくretryを実行するのが面倒だったり、Redisに障害が発生した時のリカバリー対応の運用コストが高かったためCloud Tasksに移行しました。移行して2ヶ月ほど経ちますが大きな問題なく運用コストも大幅に削減できました。

GCPには検索用のプロダクトがないためalgoliaを検索用に利用しています。 REST APIベースで検索サービスを提供してくれるSaaSでElasticsearchよりも個人的に扱いやすいAPIです。ソート条件が複数ある場合、index毎にレプリカを作る必要がありコストが高くつくため利用サービスを選びますがJicooにはソート条件があまりないためマッチしました。

Headless CMS

cmsとしてcontentfulを利用しています。

Jicooでは利用事例などの静的ページが多数あるのですがその入稿データの参照先としてcontentfulのAPIを呼び出しています。 ビルド時にgetStaticPropsを利用して数百ファイルを生成しているのとIncremental Static Regenerationを組み合わせてページ読み込み速度とデプロイ速度のトレードオフを見ながら最適化を図っています。


CI/CD

GCPのCloud BuildとGithub Actionsを併用してCI/CDを行なっています。

自動テスト実行

Pull Requestが作られるとTypeScriptのコンパイルとjestで書かれた自動テストが実行され、成功しないとmasterにmergeできないようにしています。

デプロイ

masterにPull RequestがmergeされるとCloud Buildが実行されproduction環境のCloud Runへのデプロイが実行されます。


監視

サービスの死活監視はDataDog、 RPMはNewRelicそしてエラー監視はSentryを採用しています。


まとめ

サービスが正式リリースして1年が過ぎますが、プロダクトの成長と共に問題もいくつか発生して今のCloud Run中心の構成になりましたが最近は安定してサービスを提供する事ができています。 今後もさらなるサービスの成長に貢献できる変化を取り入れつつ運用していきたいと思います。


一緒に開発してくれるメンバーを募集

Jicooはエンジニアを積極採用中ですので、新しい技術を積極的に投資をしていく環境に興味がある方、サービスを企画からガシガシ作っていきたい方は是非ご応募をお願いします!

エンジニアとして一緒に働いてみたい方はこちらをご確認ください。 https://www.jicoo.com/careers

シェア
公式SNS
TwitterFacebook

Jicooのアップデート情報や時間の効率的な使い方に役立つ情報を発信しています。