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

Firestore事务疑似允许并发编辑,出现储物柜编号重复分配问题

问题背景

我们长期使用以下Cloud Function,从单个Firestore文档内的唯一储物柜编号数组中为用户分配单个编号:

function grabLocker(){
    return admin.firestore().runTransaction(async (t) => {              
        var lockerDoc = await t.get(lockerref);
        if(lockerDoc && lockerDoc.data()){
            var lockerArr = lockerDoc.data().lockers ? lockerDoc.data().lockers : [];                                       
            if (lockerArr.length > 0){
                var randomIndex = Math.floor(Math.random()*((lockerArr.length - 1)-0+1)+0);
                var newLockers = lockerArr.slice(0,randomIndex).concat(lockerArr.slice(randomIndex + 1));
                var userLocker = lockerArr.slice(randomIndex, randomIndex + 1);
                t.update(lockerref, {'lockers': newLockers});
                return {status: 'succes', locker: userLocker[0]};
            }
            return {status: 'empty'};
        }
        return {status: 'empty'};
    });
}

Firestore文档截图

在最近的活动中,该脚本为600名申请储物柜的用户中的8人分配了重复编号,我们多次确认数组内编号均为唯一值,请问为何Firestore事务似乎允许并发编辑导致此问题?


问题原因

并非Firestore事务允许并发编辑,而是事务重试机制结合随机选号逻辑,在高并发场景下触发了重复分配。

Firestore事务的核心机制是:若事务读取文档后,该文档被其他事务修改,当前事务会自动重试整个函数逻辑。你的代码中,每次重试都会重新读取最新的储物柜数组,再生成随机索引选号。

当大量请求并发触发时,多个事务可能在同一时间窗口读取到相同的原始数组,选中同一个索引对应的储物柜编号。第一个提交成功的事务会移除该编号,后续事务提交时会检测到冲突并重试——但重试时,若随机索引再次选中某个编号,而该编号刚好被另一并发事务同时选中并提交,就会出现重复分配。尤其是当数组剩余编号越少时,这种重复概率会显著升高。

另外,代码中status字段存在拼写错误(succes应为success),但这不会直接导致重复分配问题。


修复方案

要彻底解决重复分配,需修改选号逻辑,避免随机选号带来的并发冲突:

  • 固定位置取号:直接从数组头部或尾部取号(比如取第一个元素),这样每次事务处理的取号逻辑是确定的,重试时会自动取最新数组的对应位置元素,确保每个编号仅被分配一次。示例修改:
    if (lockerArr.length > 0){
        // 改为取数组第一个元素
        var userLocker = lockerArr[0];
        var newLockers = lockerArr.slice(1);
        t.update(lockerref, {'lockers': newLockers});
        return {status: 'success', locker: userLocker};
    }
    
  • 串行化处理:将储物柜分配请求放入队列,串行处理,彻底避免并发冲突,但会增加系统复杂度。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 12:47:17