最優方案實現同步數據至HUBSPOT

需求

須要把數據庫中全部符合條件的user用戶信息(大概 6W 條信息)都發送至第三方網站 hubspot 上。要求數據有更改或者有新的符合條件的數據,能動態更新至 hubspot (最大能夠延遲一天更新最新數據)。php

實現

實現一

個人想法是:git

新建一張hubspot_data表,表裏存儲全部要發送的用戶信息。github

表中有個字段is_need_send , 0 表明不須要發送至 hubspot ,1 表明須要發送。sql

先寫一個腳本,把全部的數據到生成至 hubspot_data 表,is_need_send 設置爲 1 。數據庫

再弄兩個定時任務:json

第一個定時任務負責發送hubspot_data表數據至hubspot。api

每3分鐘獲取300條is_need_send=1的數據,
經過hubspot提供的api分三次發送
(該API限制爲一次最多發送100個用戶)至hubspot 。 
發送完以後設置此300條用戶的is_need_send=0.

第二個定時任務負責更新hubspot_data表數據緩存

天天第一次運行時獲取全部符合條件的user用戶信息,
存入到緩存文件中,
後面每次運行則從該緩存腳本中獲取前300條信息,
循環和 hubspot_data 表中的數據對比,
只要有一個字段值不同,則更新數據,
若是不存在則插入,最後設置is_need_update=1.

可是這種方式被否決了。服務器

緣由在於,6W的總量,天天須要更新的數據量只有600左右,爲了這600條用戶的更新,每次腳本運行都要執行大量 sql 來對比數據。也就是說 ,其中 90%的操做都是廢的。app

實現二

還有種方式:在代碼中找到全部須要發送的用戶信息字段,只要有更改,就手動添加一條語句,來更新 hubspot_data 表數據(或者直接發送)。

可是這種方式被我否決了 。

緣由在於這是個維護已超10年的老項目,裏面的代碼邏輯異常複雜。誰也不知道哪裏就有個地方修改了須要的字段。這個思路的工程量太大~

實現三

最後選中了第三個方法:給 hubspot_data 表增長一個爲 is_need_update, 0 表明不須要更新數據,1表明須要更新數據。再給涉及到數據數據表加觸發器,表數據有更新插入刪除時,觸發器觸發 hubspot_data 對應表中用戶,更改 is_need_update=1 。上面的第二個定時任務就能夠更改成天天運行3次,每次獲取300條is_need_update=1 的數據更新數據,更新以後設置 is_need_update=0

第三種方式,開發的代碼量最少,對數據庫的操做也降到了最低。

坑一

hubspot 的屬性有個叫 datetime 的類型。這個類型的屬性值,是毫秒級的。這個類型的屬性,只能經過API建立。
還有個叫 Date 的類型,這個類型的屬性,能夠在 hubspot 網站上建立,可是他必須是 UTC 時區的凌晨,不然更新數據會失敗。

關於data類型屬性的介紹戳這裏。

坑二

hubspot 有個 api 能夠一次更新多條信息,可是若是這多條信息中,有一條更新失敗,那麼該次請求全部的數據都更新失敗。因此必須處理更新失敗的用戶,將失敗用戶 is_need_update 設置爲非0非1(以防每次更新數據遇到錯誤用戶信息一直更新失敗又一直更新陷入循環)。

批量更新
原文:When using this endpoint, please keep in mind that any errors with a single contact in your batch will prevent the entire batch from processing. If this happens, we'll return a 400 response with additional details as to the cause.

坑三

最後一個坑:由於我知道天天的更新量大概在600條左右,天天運行3次,大概一次也就更新200數據,因此第二條更新數據的定時任務沒有限定條數 。 正常狀況下沒任何問題。直到有一天,,,,,

須要給 users表增長一個字段,設置全部的用戶該字段值爲 1 。 因爲觸發器的存在,致使 hubspot_data 全部數據的is_need_update都爲 1 .因此該定時任務運行時須要 6W 數據數據作循環處理,服務器妥妥的掛了。。。。(服務器只有1G內存)。

觸發器

貼上其中2條觸發器

## edit updateUserCIM trigger(update user CIM info trigger)
DELIMITER ;;
create trigger updateUserCIM
             after UPDATE on user_cim_details
             for each row
BEGIN
  update hubspot_data SET is_need_update = 1 where user_id = NEW.user_id;
END;;
DELIMITER ;
## create insert_hubspot trigger( insert user trigger)
DROP TRIGGER insert_hubspot;
DELIMITER ;;
create trigger insert_hubspot
             after INSERT on users
             for each row
BEGIN
  REPLACE into hubspot_data(user_id, email,is_need_update) VALUE (NEW.id,NEW.email,1);
END;;
DELIMITER ;
## edit UserStatusUpdateDate trigger(update user's status trigger)
DELIMITER ;;
create trigger UserStatusUpdateDate
     before UPDATE on users
     for each row
IF NOT(NEW.user_status <=> OLD.user_status) THEN
update hubspot_data
    set is_need_update = CASE
    when new.user_status in ('C','G') then 2 else 1
    end
where user_id = old.id;
END IF;;
DELIMITER ;

結尾

結尾沒啥好說的啦,此文不是講如何對接、調用 hubspotapi ,主要講如何分析一個需求,以最優方案解決。

關於如何對接、調用 hubspot API ,能夠閱讀其開發文檔:HubSpot API Overview , 這個 api 文檔網頁,能夠直接在上面測試,很是讚的一個功能。

github 上有別人寫好的類庫能夠直接拿來用 hubspot 。不過這個使用的 api 都是比較古老的。限於的php 版本,我只能用這個了。最新的 API 的使用,能夠參閱其 README.md文件。其中他沒有實現批量更新的 API ,這裏給出我本身的一個實現:

src/Fungku/HubSpot/API/Contacts.php文件加入如下代碼:

/**
 * Create a group of contacts or update them if they already exist.
 *
 * eg:
 * array(
 * array('email'=>'testBatch5@qq.com','param'=>array('firstname'=>'JasonT5','lastname'=>'Zhang5','phone'=>'555-122-2325','ispaid'=>'No')),
 * array('email'=>'testBatch6@qq.com','param'=>array('firstname'=>'JasonT6','lastname'=>'Zhang6','phone'=>'555-122-2326','ispaid'=>'No')),
 * array('email'=>'testBatch7@qq.com','param'=>array('firstname'=>'JasonT7','lastname'=>'Zhang7','phone'=>'555-122-2327','ispaid'=>'No')),
 * array('email'=>'testBatch8@qq.com','param'=>array('firstname'=>'JasonT8','lastname'=>'Zhang8','phone'=>'555-122-2328','ispaid'=>'No')),
 * )
 *
 * @param params: array of properties and property values for new contact, email is required
 *
 * @return Response body with JSON object
 * for created Contact from HTTP POST request
 *
 * @throws HubSpotException
 **/
public function batch_create_or_update($params){
    $endpoint = 'contact/batch/';
    $properties = array();
    foreach ($params as $k => $param) {
        $propertie = array();
        foreach ($param['param'] as $key => $value){
            array_push($propertie, array("property"=>$key,"value"=>$value));
        }
        $properties[$k]['properties'] = $propertie;
        if(!empty($param['vid'])){
            $properties[$k]['vid'] = $param['vid'];
        }elseif (!empty($param['email'])){
            $properties[$k]['email'] = $param['email'];
        }else
            continue;
    }
    $properties = json_encode($properties);
    try{
        return json_decode($this->execute_JSON_post_request($this->get_request_url($endpoint,null),$properties));
    } catch (HubSpotException $e) {
        throw new HubSpotException('Unable to create contact: ' . $e);
    }
}

若是開發過程當中遇到任何問題,能夠到 hubspot開發者社區尋求幫助,支持github帳號登陸哦~

相關文章
相關標籤/搜索