最优方案实现同步数据至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帐号登陆哦~

相关文章
相关标签/搜索