You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

循环逻辑异常:Slack API数据仅部分写入数据库问题排查

问题排查:Slack API数据仅部分写入数据库

背景说明

应用调用Slack API获取指定日期的gzip格式响应,解压为JSON文件(单日期约1500条记录),计算各字段累计值后写入数据库,最终写入的数据格式如下:

{ 
 "date" : "2022-09-01",
 "number_of_users" :  1503,
 "is_billable_seat" : 1202,
 "is_active_ios" : 600,
 "is_active_android" : 400,
 "is_active_desktop" :503
}

当前传入包含4个日期的数组,通过循环调用API并写入数据库,但仅2天数据成功写入数据库,核心代码如下:

listDate = ['2022-09-01', '2022-09-02', '2022-09-03', '2022-09-04']

for(let i=0; i<listDate.length; i++){
        
        let arr = []; let data_to_db = [];
        
        let date = listDate[i]

        let URL = `${process.env.slackapi}?type=member&date=${date}&pretty=1`;

        request(URL, {     //fetch slack data from API
        headers: {
            Authorization: 'Bearer ' +  process.env.accesstoken,
        }})
            .pipe(zlib.createGunzip())
            .pipe(
            concat(async (stringBuffer) => {
                result = stringBuffer.toString()
                fs.writeFileSync('gzip-file-' + date + '.json', result, (error) => {
                    if (error) throw error;
                });

                const allFileContents = fs.readFileSync('gzip-file-' + date + '.json', 'utf-8');
                    allFileContents.split(/\r?\n/).forEach(line =>  {
                    arr.push(line)
                    });

                            
            arr.map(obj => {
                if(obj){
                    const myObj = JSON.parse(obj);
                    data_to_db["date"] = myObj.date
                    data_to_db["number_of_users"] = ++number_of_users
                    data_to_db["is_billable_seat"] = myObj.is_billable_seat == true ? is_billable_seat += 1 : is_billable_seat
                    data_to_db["is_active_ios"] = myObj.is_active_ios == true ? is_active_ios += 1 : is_active_ios
                    data_to_db["is_active_android"] = myObj.is_active_android == true ? is_active_android += 1 : is_active_android
                    data_to_db["is_active_desktop"] = myObj.is_active_desktop == true ? is_active_desktop += 1 : is_active_desktop
                }

            })


            console.log(data_to_db)

            connection.connect( async() => {   

                console.log("DB connected!!", date)
                   
                await pushSlackDataToDatabase(data_to_db, connection) //push slack data to DB
            })
    
           })
          );

        
    }

错误原因排查

1. 计数器变量未隔离,存在竞态条件

代码中number_of_users、is_billable_seat等计数器变量未在循环内部声明初始化,属于全局/外部共享变量。由于request是异步操作,4个日期的请求会同时发起,异步回调会交叉执行,多个回调同时修改同一个计数器:

  • 比如第一个日期的回调还在统计用户数,第二个日期的回调已经开始累加同一个number_of_users,最终导致部分日期的统计值错误,写入数据库时可能因数据无效被拒绝,或者后执行的回调覆盖先执行的,导致仅部分数据留存。

2. 重复建立数据库连接

每次循环的异步回调中都调用connection.connect(),而数据库连接通常是单例模式,重复调用会导致:

  • 连接池资源耗尽,后续连接请求被拒绝,无法写入数据库;
  • 连接状态冲突,部分写入操作因连接异常失败。

3. 不必要的文件IO操作(间接隐患)

代码中先将解压后的内容写入本地JSON文件,再立即读取回来处理,完全可以直接使用result变量处理数据:

  • 同步文件写入/读取会阻塞事件循环,拖慢异步回调的执行速度,加剧竞态条件的影响;
  • 若文件系统出现异常(如权限不足),会导致数据处理中断,无法写入数据库。

4. 数据载体类型错误

data_to_db被定义为数组[],但实际当作对象使用(赋值键值对),虽然JS允许数组作为对象操作,但这种不规范的写法可能导致后续数据库写入函数解析数据时出错,直接导致写入失败。

修复建议

  1. 在循环内初始化计数器:将number_of_users、is_billable_seat等变量放在循环内部,确保每个日期的统计独立:
for(let i=0; i<listDate.length; i++){
    let arr = []; 
    let data_to_db = {}; // 改为对象类型
    let date = listDate[i];
    // 初始化计数器
    let number_of_users = 0;
    let is_billable_seat = 0;
    let is_active_ios = 0;
    let is_active_android = 0;
    let is_active_desktop = 0;
    
    // 后续代码...
}
  1. 提前建立数据库连接:在循环外部完成数据库连接初始化,回调中直接使用已建立的连接:
// 循环外先连接数据库
connection.connect(async () => {
    console.log("DB connected!!");
    for(let i=0; i<listDate.length; i++){
        // 循环内直接使用connection,不再调用connect
        // 后续代码...
        await pushSlackDataToDatabase(data_to_db, connection);
    }
});
  1. 移除冗余文件IO:直接使用解压后的result处理数据,跳过写入文件再读取的步骤:
concat(async (stringBuffer) => {
    const result = stringBuffer.toString();
    const allFileContents = result;
    allFileContents.split(/\r?\n/).forEach(line => {
        arr.push(line);
    });
    // 后续统计代码...
})
  1. 修正数据载体类型:将data_to_db定义为对象{},符合键值对数据的使用场景。

内容的提问来源于stack exchange,提问作者Winterella

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 07:30:53