
ゼストでPEM(プロダクトエンジニアリングマネージャー)兼バックエンドエンジニアをやっている今井です。
この記事は、ゼスト Advent Calendar 2025(https://adventar.org/calendars/12198)の24日目の記事です。
「それはそう。」なタイトルを目指してみました。
訪問予定を管理する弊社プロダクト、ZEST SCHEDULEでは、他社システムとのデータ連携ができる機能を提供しています。
今でこそ多数の他社システムとの連携機能を提供させていただいていますが、ここに至るまでには運用上、 設計上の難しさがいくつもありました。
今回は、データ連携機能を開発する際の留意点のうち、特に気にしておいた方がいいであろうポイントを、いくつか抜粋して書いていこうと思います。
データ連携機能について
データ連携と言っても様々あるので、軽く前提をご説明しておきます。
弊社が提供するZEST SCHEDULEは訪問予定を管理するプロダクトですが、予定データ以外にも、例えば以下のようなマスタ系のデータが必要になります。
- 利用者:訪問先の利用者さんのデータ。
- 職員:訪問を行う職員さんのデータ。
そして、連携先となる他社システムは、主にレセコンや電子カルテなどのシステムです。
ある他社システムとの連携を一例としてあげると、
- マスタ系のデータは他社システムで管理されている → 他社システムの保持しているマスタ系データをZEST SCHEDULEに同期させ、それを使って予定を作っていく
- 予定はZEST SCHEDULEで管理している → 実績を他社システムに登録するため、ZEST SCHEDULEから他社システムにデータを書き込みにいく
といったものがあります。
簡単にまとめると、「データの種類が複数ある」「データの流れが双方向な場合がある」ってことです。
開発にあたって気にしておいた方がいいこと
連携のタイミング
データ連携といってパッと思いつくのはリアルタイム連携ですが、実は現場のオペレーションを追っていくと、意外とそれ以外のニーズがあったりします。
例えば弊社のプロダクトの場合、「ZEST SCHEDULEである期間の予定をFIXさせてからまとめて送りたい」といったニーズがあったりするので、「ある1週間の予定を連携する」といった操作をユーザーが明示的に行う仕様にしています。
弊社が提供している連携機能の中にはリアルタイムな連携もありますが、その場合には少し工夫が必要で、実際にはスケジューラによる定期実行で擬似リアルタイムにしていたりします その理由は後述のRate Limitのところで書きます。
連携差分の管理
最後にデータ連携された以降の更新差分を、どのように管理するか、という話です。
弊社では、連携対象のデータの更新イベントを拾って、非同期で差分データを積み上げるような仕組みをとっています。
しかしこれ、非同期であるが故に、気をつけておかないと、「反映実行や連続したデータ更新がほぼ同時に行われた場合にデータが微妙に壊れる」みたいなことが割とおきます。
何パターンか構成を作ってみてわかったこととしては、「一つのテーブルに対しては1箇所からしか更新をかけない」ということを徹底すると、大体防げます。
どういうことかというと、例えば反映履歴テーブルみたいなテーブルを作った時に、そのテーブルのカラムに反映済みフラグみたいなものを持たせたくなるのですが、そうすると差分積み上げ処理と反映結果更新処理で同じレコードを触ることになり、事故りやすいです。
なので最近は、反映履歴テーブルと反映結果テーブルを分けておくことで、反映履歴テーブルを触るのは差分積み上げ処理だけ、反映結果テーブルを触るのは反映結果更新処理だけと分けることで、ほとんど問題は起きなくなりました。
連携エラーとリトライ
自社のアプリケーションの中だけで完結する機能とは違い、他社システムとの連携は不安定になりやすいです。
ネットワークが不安定だったり、想定していなかったレスポンスが返ってきたり、ユーザーが設定したAPIキーが間違っていたり、原因も広いです。
全てを想定した作りにしておくのは厳しいので、弊社では以下の点を考慮しつつ、ある程度あそびを持たせる構成にしています。
- エラーメッセージはユーザーにネクストアクションを促すものにする
- ユーザー起因(APIキー設定ミスなど)のものは解消のアクションを明示する
- 連携先起因(≒こちらでは原因が追いきれない)のものは操作のリトライを促す
- 「何度やってもダメなら問い合わせください」で個別対応に倒す
- エラー発生自体にユーザーが気づけるようにする
- 普通に考えれば「操作したんだからちゃんと動いて当然」だけど実際他システムへの操作は失敗することがある
- バッジなどでエラー対象のデータを目立たせるなどしておき、極力事故を防ぐ
- システムアラートなどで未知の事象に気付けるようにする
- 運用しながら改善していくことをある程度許容しておく
Rate Limit
連携先システムのAPIの制約に関してです。
これが一番難儀かもです。
大体どのシステムもRate Limitが決められていると思いますが、このRate Limitの単位が、結構バラバラです。
ユーザーの法人単位に定められているものもあれば、連携機能を開発するベンダー単位に定められているものもあります。
となると、同じような連携の仕様でも連携先によって裏側は全然違う構成にしないといけなかったりします。
例えば「連携機能を開発するベンダー単位」で考えた場合、これは「ゼストさんからのリクエストは毎分〇〇回まで!」という仕様ってことなので、簡単にやるならキューイングのサービスで流量を絞れば実現できると思います。
一方で、ややサービスに依存する形になり、細かい連携タイミングの制御がやりにくくなるので、連携先のサーバが落ちてしまった等でメッセージが消滅するリスクなど、考えなければいけないこともあります。
逆に「ユーザーの法人単位」で考えると、それぞれの法人でリクエスト数を管理しないといけなくなります。でも法人が増えるたびにキューを増やすとかはあまり現実的ではないと思っています。
そこで「連携のタイミング」で前述したスケジューラによる定期実行で擬似リアルタイムの話が出てきて、「毎分法人ごとにRate Limit範囲内になる分だけ反映対象を集めてAPI実行を行う」、みたいな構成をとるわけです。
まとめ
最近専ら連携機能ばかり作っているので多少こなれてきましたが、やる前はここまで考えることが多いとは夢にも思ってませんでした。
今回はあまり細かい構成までは言及しませんでしたが、そのうちに実際のアーキテクチャ含めた構成なんかもご紹介できたらいいなと思っています。