heroku connect戦記

heroku connect戦記

社内で使用しているいくつかのデータベースやウェブAPIと、Salesforceのデータを連携させるにあたり、herokuにpostgreSQLをいれ、そこにheroku connectを入れれば、何せポスグレ、こちらの思い通りになる、と思って導入したところ、たびたび遭遇するエラーに気が狂いそうになっています。

 

そんなheroku connectとの戦いの記録をここに記す

 

Mappings: Nantoka__c Logs Edit Delete Reload Poll Now

Salesforce上のNantoka__cオブジェクトと同期するマッピングを設定したところ、エラーが。

Nantoka__c contains formula or roll-up summary fields. Updates to these fields in Salesforce may not be synced to the database.Read more
うんうん、SF側に積み上げ項目や数式の項目は同期できないってことだね、そりゃそうだよね、危ないもんね。
で、どこの項目が引っかかったのかな。

Read moreの内容
Changes to formula and roll-up summary fields that are driven by a change in a parent object do not update the SystemModStamp of the child object – this means that the object will not be synchronized by Heroku Connect.
だから、どの項目のことなのかな……?

マッピング画面にはどれが積み上げとか全く書いていないので、SFのオブジェクトの設定画面と見比べて、フィールド名で、数式や積み上げのフィールドを虱潰しに確認しました。

同期できないフィールドは、マッピング画面でチェックできないようにしてほしかった。

=> 追記

テーブル内にある数値の計算合計など、テーブル内で完結している数式は、同期されるのではないかというコメントをTwitterでいただきました。

 

更新前と更新後の内容が同じだと更新日時が更新されてもSalesforceに反映されない

だったら反映しなくていいじゃないかと思われるかもしれませんが、何故こんなことをする必要があったかを含めて経緯を説明します。

Salesforceに複数選択項目があったのですが、それを、一つしか選べない選択項目に変えることになりました。ルックアップ検索の対象にしたかったのですが、複数選択のままではできなかったので。
ほとんど複数を選択することがなかったので、項目を変えても、更新前後の内容は同じテキストが入ります。

①create table public.tmpaccount as select sfid,addfield__c from salesforce.account where addfield__c != ”
addfield__c が、今回いじりたいフィールドです。
バックアップをとります。

②update public.tmpaccount set addfield__c=’プラム’ where addfield__c=’プラム;ケルシー’
複数選択されていたデータが少しだけあったので、強制的に一つに。

③Salesforceでaddfield__c項目を単独選択形式に変更。既存データはすべて削除されてしまいました。

④update salesforce.account set addfield__c=public.tmpaccount.addfield__c from public.tmpaccount where salesforce.account.sfid=public.tmpaccount.sfid
バックアップから戻しました。

(余談だけど、最初うっかりmySQLと同じ書き方をしたらエラーになった。
× update salesforce.account,public.tmpaccount set salesforce.account.addfield__c=public.tmpaccount.addfield__c where salesforce.account.sfid=public.tmpaccount.sfid )

しかし、Salesforceのaddfield__cは、いつまでも空白のまま。heroku connectには、ちゃんとデータが戻っているのに……。

③の後、一定時間置いて、Salesforceで空白になったaddfield__cが、heroku connectでも同期されてクリアされていることを確認してからじゃないと、④を実行してはいけなかった。
何故なら、heroku connect上では、②と④のデータの状態が同じなので、更新したとみなされず、Salesforce側に反映してくれない。

heroku connectはリアルタイムではないということを忘れてはいけません。

どうしたかというと、heroku connect側のaddfield__cを全てクリアして、時間を置いて同期を確認してから、また④を実行しました。

 

桁数が違うとか必須項目が入ってないとか項目ごとにエラーメッセージがあって当然同期できてない行がある

Salesforceから同期したheroku connectに限ってそんなことがあるはずないじゃないですかー、データローダじゃあるまいしー、と思ったんですけど。

マッピングの後で、Salesforce側に追加した制約が、heroku connectに反映されていないため、SFには入れられないデータを入れたため、こういうことが起こりました。

Salesforceも、制約をつける前に作ったデータは適用外で、閲覧はできるけれど更新はできなかったりします。しかし放置しておけば無害。
ですが、heroku connectではSalesforceと違い、SQLを使ってまとめて更新するのが主なので、前に作ったデータも対象に入れてしまうことが多々あります。

更新されれば、同期を試みて、エラーになります。

ちゃんとデータを整えてからデータ形式を変え、同期を確認の後、heroku connectをマッピングをし直しましょう。

それが難しいなら、古いデータに触れないよう、update文の条件に、年月日を入れましょう。

 

NantokaUpsertTrg: System.LimitException: Too many SOQL queries: 101

そんなエラーメッセージが表示された行が……。connectでまで見たくなかったガバナ制限。

Salesforceにapexトリガーを入れてて、そこにSOQLのSelect文があったのを忘れていました。
Nantoka__cは、データローダも使いませんし、他のところでは100件以上まとめて更新されることはないオブジェクトです。
しかしheroku connectはデータローダのように任意の行数ずつ同期するようなことはできない。更新しないようにするしかない。

幸いにも、connectを使って同期するレコードタイプのデータは、Select文の結果に基づいて行われる、コールアウトとか含まれていてまたガバナ制限にかかりそうなapexの処理は対象外。

ApexトリガのSelect文を、Salesforceのフローで判断するように移行すれば解決するような気がする。
しかしまだうつしてない。運用でカバーしてる。

 

ロールバックできない

別のシステムで使っているデータベースと、heroku connectを同期させていたのです。
途中でエラーが出て、別のデータベースの方はきれいにロールバックされているのに、connectとSalesforceにはエラーで引っかかる前のデータがいっぱい作られてしまいました。

おかしいな、heroku connectへの接続にも、トランザクションちゃんと設定してたんだけどな。

apexでSOQLがロールバックできないから、こっちもそうなんですね。がっかりだ。

 

duplicate value found:…..

上のとおり、別のシステムで使っているデータベースと、heroku connectを同期させています。

同期のバッチプログラムは最低でも15分は空けて実行しないと、heroku connectとSalesforceの同期もリアルタイムではないので、タイミングがあわずにconnect上に重複データが作られたりしました。
同期プログラムをもっとしっかり作ればいいのかもしれませんが、もうめんどうくさい。しかも、他のウェブAPIとも同期してるバッチだから、けっこう仕組みが複雑。

どうせ自動実行なので、30分間隔で実行しています。

 

復旧方法

エラーを一つ一つ確認し、なんとか修正したデータをどうやったらSalesforceに反映できるのでしょうか。

これが正しいやり方なのかわかりません。もっとスマートに復旧できる方法もあるのかもしれません。

エラーの原因となったデータをSQLやDB管理ツール(MS AccessのODBCやphpPgAdminなどを使っています)で直しても、同期状態を表す _hc_lastop はFAILEDのまま。
正常に同期されているデータはSYNCEDとなります。

強制的にFAILEDをUPDATEDに書き換えます。
しばらくすると、PENDING、INSERTED、SYNCED、と状態を変え、Salesforceと同期されます。

入門ヘロクコネクターの魔法の呪文を貼っておきます:

update salesforce.nantoka__c set _hc_lastop=’UPDATED’ where id in (select id from salesforce.nantoka__c where _hc_lastop=’FAILED’ and _hc_err like ‘%Too many SOQL queries%’ limit 50)

 

俺たちの戦いはこれからだ!
(打ち切ってほしい)