Heroku Tips (5) Heroku Connect

January 22, 2019 Naoki Kitaarashi

皆さん、こんにちは。アピリオ北嵐です。5回目となる今回は Heroku Connectを取り上げてみたいと思います。Heroku Connectはその名前にあるように Salesforce と Heroku間のデータを”コネクト”つまり同期するアドオンになり、Salesforce組織と連携したアプリケーションをHeroku上に構築するためには欠かせないサービスになります。リリースから2年以上が経過しており、当初から比べると機能面、性能面での向上が図られています。今回のブログではHeroku Connectの基本的な仕組み、提供する機能、そして実プロジェクトで利用する際の考慮点について書いていきたいと思います。

1. SalesforceとHeroku間でのデータ同期

Heroku Connectは、Salesforce上のオブジェクトとHeroku Postgres上のテーブルを1:1でマッピングして、自動的に同期を行うサービスです。HerokuからSalesforceへの同期は標準のSOAP/Bulk APIで行われ、Salesforce組織への追加設定は不要です。オブジェクトであれば同期することが可能なため、標準オブジェクト、カスタムオブジェクト、カスタム設定、カスタムメタデータが同期対象となります(全てのオブジェクトがサポートされているわけではないため、詳しくはこちらを参照)。Heroku側での簡単な設定により任意の数のオブジェクトを同期させることができます。Heroku Connectを利用するには、アドオンとして「Heroku Connect」と「Heroku Postgres」を

現在のHeroku Connectは一方向同期と双方向同期の2種類の同期をサポートしています。ただし一方向同期でサポートされているのは Salesforce → Heroku 間だけで、Heroku →  Salesforce のみの同期はサポートされていないことに注意して下さい。HerokuからSalesforceへ値を同期させたい場合は双方向同期を選択する必要があります。

データの同期はリアルタイムに行われるわけではなく、Salesforce → Heroku間の同期については下記の2つのモードが提供されています。

ポーリングモード

  • 設定した時間間隔(2分〜60分)でSalesforce側オブジェクトをポーリングし、レコードの変更(作成/更新/削除)を検知してHeroku Postgres側への同期を行う
  • ポーリング間隔はSalesforceのオブジェクト単位に設定可能
 
ストリーミングモード
  • Salesforce側オブジェクトでレコードの変更が行われると、ストリーミングAPIによってHeroku Connectに通知が送られる。Heroku Connectはこの通知を受けると即時ポーリングを開始する
  • Salesforce側オブジェクトで連続して変更が行われた場合は、次にポーリングが実施されるのは10秒後になるため、変更が頻繁に発生する場合は、常に即時ポーリングが実施されるわけではない
 
双方向同期を選択した場合は上記のSalesforce → Heroku 同期に加えて、下記のHeroku → Salesforce 同期が行われます。
 
  • Postgres側のテーブルに変更が入ると、ログテーブルに変更内容が書き込まれる
  • Heroku ConnectはPostgresテーブルへの変更を監視しており、通常は数秒以内にSalesforceへの同期が行われる
  • Salesforce側での更新(IDの採番、数式フィールドの計算等)はSync backされ、Postgres側に反映される
HerokuからSalesforceへの同期の仕組みは少し複雑であり、管理用のログテーブルを介してPostgres側での変更はSalesforce側に通知されます。また、Salesforce側の管理項目(ID、LastModifiedDateなど)や数式などの項目はSalesforce側でしか生成・更新できないため、Heroku -→ Salesforce の同期が完了した後に Sync backによりHeroku側に戻されるようになっています。
 
ログテーブルの実体は _trigger_logテーブルであり、直近24時間以内に発生した書き込みが保持されます。24時間を経過したレコードは _trigger_log_archiveテーブルに移動されます。双方向同期で障害が発生した場合は、このテーブルの中身を確認して、同期時の状況をレコード単位で詳細に調査することができます。
 
2. オブジェクトのマッピング

Heroku Connectによる同期設定は非常に簡単であり、接続対象のSalesforce組織にログインした後は、画面上でマッピング対象のオブジェクトを選択するだけです。自動的に対象オブジェクトのメタデータからPostgres上の同期テーブルが作成され、すぐに初回の同期が始まります。オブジェクトの全ての項目を同期させる必要はなく、同期対象の項目は画面上で選択することができます。

[オブジェクトのマッピング画面]

上記はマッピングされているオブジェクトの一覧を表示する画面であり、右上の「Create Mapping」をクリックして追加するオブジェクトを選択します。

[マッピング項目の設定画面]

上記はオブジェクトのマッピング項目と同期方法を選択する画面です。項目ごとに同期の有無をチェックボックスで選択できるだけでなく、インデックスの設定も行えます。上部の「Poll Frequency」で同期間隔を設定します。「Accelerate Polling」をチェックするとポーリングモードで同期するようになります。項目設定はいつでも変更することができ、またSalesforce側でオブジェクト定義に変更があると、Postgres側のマッピング画面ではワーニングが表示されるようになります。

双方向同期を設定するためには、オブジェクトに外部ID項目を追加する必要があります。一方向同期であれば必ずSalesforce ID(18桁)が採番されるため、このIDを各レコードを識別する一意のKeyとして使用できるのですが、双方向同期の場合はHeroku側でもレコードの挿入が可能であるため、 Heroku側でのレコード挿入時にレコードを一意に識別するKeyとして外部IDを設定する必要があります。外部IDには36桁のUUIDを使用することが推奨されています。

上記に双方向同期オブジェクトに追加する外部ID項目の例 を示します。”ユニーク”と”外部ID”属性はチェックする必要があります。

[マッピング画面における外部IDの指定]

オブジェクトに外部ID項目が設定されていると、マッピング項目の設定画面で上記のように双方向同期を選べるようになります。

なお、Salesforce のデータ型とPostgresのデータ型とのマッピングは自動的に決まります。対応についてはHeroku Connect ヘルプページのMapped data typesの章を参照してみて下さい。
 

Postgres側で自動生成されたマッピング先のテーブルには、必ず下記の2つの管理項目が追加されていて、同期状況やエラー時のログをレコードごとに確認できるようになっています。

_hc_lastop   

同期状況のステータスがセットされる                                                                                                              

PENDING : 同期待機中
INSERTED : SalesforceでレコードがINSERTされた状態
UPDATE : SalesforceでレコードがUPDATEされた状態
SYNCED : 同期完了
FAILED : 同期失敗
_hc_err  同期が失敗したときにJSON形式のエラーがセットされる

op : Salesforce側での操作
src : エラー発生元
msg : Salesforceから戻されたエラーメッセージ

 

3.  利用時の考慮点

Heroku Connectを利用する際のいくつかの考慮点についてご紹介したいと思います。
 
ガバナ制約
Heroku ConnectとSalesforce間の連携には、SOAP API や ストリーミングAPIといったガバナ制約の対象となるI/Fが使用されますが、Heroku Connectからのリクエスト数はガバナ制約にカウントされないため、組織のライセンスによる制約を受けません。
 
ストリーミングモードによる準リアルタイム同期
ストリーングモードは比較的新しく導入された方式であり、変更頻度が高くなる分システムの負荷も高くなるため、頻繁に同期する必要がないオブジェクトはポーリングモードによる通常同期を選択しておいた方が無難と考えます。以前は、ストリーングモードの使用はストリーミングAPIイベント数にカウントされガバナ制約の対象になっていましたが、前述したように現在はガバナ制約を気にせずに使用することが可能です。
ストリーミングモードを使用することでリアルタイムに近いタイミングで(準リアルタイムと表現されます)同期されますが、更新が頻繁に発生する場合は同期タイミングは10秒に1回となるため、リアルタイムで同期することが必要な場合は、Heroku Connectを使わずにSOAP/RESTによる直接同期を検討すべきでしょう。
 
数式/積み上げ集計項目
数式項目の同期には制約があります。レコード保存時に値が計算されるタイプの数式(自レコード内の項目に対する参照や計算式を使った数式)であれば、数式項目の値が更新されると変更値はHeroku側に同期されます。一方、クロスオブジェクト数式(他のオブジェクトの値を参照する数式)は、参照先のオブジェクトで値が更新されても自レコードのSystemModStampが更新されないため同期は行われず、クロスオブジェクト数式以外の項目が変更されたタイミングでしかHeroku側には同期されません。
積み上げ集計項目にも同様な制約があり、子レコードの値が更新されても親レコードの同期処理は走らないため、積み上げ集計項目もそのタイミングでは同期されません。
 
バイナリデータは対象外
ファイルが格納されるバイナリデータ型の項目は同期対象外となります。そのため、添付ファイル・オブジェクトやContentVersionオブジェクトに格納されているファイル本体は、別途 SOAP/REST API経由で取得する必要があります。
 
大量データ
Salesforceオブジェクトで2万件以上のレコードに更新が行われた場合は、SOAP APIではなく Bulk APIを使ってレコードの取得が行われます。Bulk APIにより高速にデータ連係が行われるのは良いのですが、Nullデータの取り扱いがSOAP APIと異なることに注意する必要があります(Bulk APIを使った場合、Null項目には  文字列 "#N/A" がセットされる)。
現在のバージョンではSalesforce → Heroku間のデータ同期はかなりチューニングされていて高速であり、同期にかかる処理時間が問題なるケースは少ないのではないかと考えます。項目数10個程度のオブジェクトであれば1万レコードの同期は2分程度で終わります(Salesforceの負荷状況にも影響されますので、Heroku Connectとして保証する数値ではありません)。同期は並列で実施されるため、複数のオブジェクトに同時に更新がかかっても、並行して同期が行われます。
 
短時間の連続更新
双方同期の制約として、短時間に連続更新が起こると一時的にデータの先祖返りが起こってしまうというものがあります。
前述したように、双方向同期の場合はHeroku → Salesforce間の同期の後に、Salesforce → Heroku 間のSync back処理(SF側で採番・更新した値がHeroku側に連携される)が行われるのですが、この時に更新した値そのものも戻ってきます。このSync backの処理は通常は数秒以内に終わるのですが、更新とSync backの間に同じ項目に対して連続して更新が入ると、下記のように一時的にデータが先祖返りしてしまう状況が発生します。全ての更新のSync back処理が終われば正しい値になるため、必ずしもこの挙動が大きな問題に繋がるわけではありませんが、私が参画したプロジェクトでは、更新項目がカウンター値であったためカウンター値の計算が途中で正しくなくなるという障害が起こりました。
この挙動はHeroku Connectの同期の仕組み上回避することが難しいため、アプリ側で対応するか(Sync backが完了するまで更新をブロックする等)、短時間に連続して更新が発生する場合は利用を避けるといった対応が必要となります。
 
 
数値型の桁数
Salesforceの数値型は整数部と小数部込みで最大18桁まで保持できることになっています。このSalesforceの数値型はPostgresのDouble Precisionという浮動小数点データ型にマッピングされるのですが、Double Precision型は15桁までの整数および小数しか保持できないため、厳密にはSalesforceの数値型と互換が取れていません。数値型の項目に16桁以上の数値(1京以上)が格納されるケースはそうそうないため、この制約が問題になることはほとんどないでしょうが、仕様としては理解しておくと良いです。
 
タイムスタンプ項目とUTC
ご存じのように、Salesforceの日付/時刻型に格納される時刻はUTC(世界協定時刻)であり、JST(日本時刻)から-9時間されています。同様にHeroku Connectで同期されたPostgresのタイムスタンプ型にもUTC時間がセットされますので、Heroku側のアプリもUTC時間を取り扱う必要があり、入出力においてJSTとの変換が必要になります。
 
まとめ
 
Heroku はPaaSプラットフォーム単体として優れた環境であり、最小限の手間でサーバープラットフォームの構築と維持ができ、開発生産性も高いです。一方、Salesforceの傘下にあることもあり、Salesforceと連携したカスタムアプリケーション構築のプラットフォームとして検討されることも多いです。このSalesforceとの連携において大きな効果を発揮するのがHeroku Connectです。設定のみで2つのプラットフォーム間のデータを同期できるため、少ない工数でSalesforceを拡張するシームレスなアプリケーションを構築できるようになります。1方向同期のみの場合と比べると双方向同期が必要な場合は設計時の考慮点は多くなります。特にデータの更新頻度と同期のリアルタイム性の両面からHeroku Connectを使うのかSOAP/RESTによる直接更新を行うかをよく検討する必要があるでしょう。
 
Heroku Connectはリリースから2年を超えエンタープライズな環境での事例も出てきており、十分に実用的なサービスに育ってきていると思います。本稿がHeroku Connectの採用を検討しているエンジニアの一助になれば幸いです。

著者について

某大手SIベンダーを退職し2015年3月からアピリオの一員としてクラウドの世界に身を投じているシニアエンジニアです。Salesforceを極めようと精進していたら、いつの間にかエンタープライズのHerokuアプリ開発で再びJavaの世界に戻って来ている最近です。クラウドという広大な技術の波に翻弄されつつも、やはりクラウドは最高に面白いなと感じている毎日です。

Naoki Kitaarashi のコンテンツをもっと見る
戻る
Heroku Tips(6) BlazeMeter による負荷テスト
Heroku Tips(6) BlazeMeter による負荷テスト

Heroku Tipsの6回目は、Heroku アドオンのBlazeMeterをご紹介したいと思います。クラウドの世界においても構築したWebアプリケーションに対する負荷テストは従来と同様に重要なものです。今回ご紹...

次へ
Heroku Tips(4) Gitlabで自動デプロイ
Heroku Tips(4) Gitlabで自動デプロイ

Herokuで開発を行う際にコード管理とサーバーへのデプロイをどのように実施していますか?GitLab CI の仕組みを利用して、masterブランチへのコミット時に自動的にHerokuサーバーにデプロイすることも...

アピリオまでお気軽にお問合せください

ご質問はこちら