扣子中需通过redis分布式锁防止并发冲突,具体包括:准备redis连接与唯一锁标识(lock:{bot_id}:{scene}:{resource_id})、原子加锁(set key value nx px ms)、安全释放锁(lua脚本校验value后del)。
☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 多模态理解力帮你轻松跨越从0到1的创作门槛☜☜☜

扣子中接入Redis分布式锁防止并发冲突
当多个用户同时触发同一扣子(Coze Bot)工作流,例如秒杀下单、库存校验或订单创建时,若不加锁,极易出现超卖、重复写库、状态错乱等数据异常。扣子本身无内置分布式锁能力,必须通过外部Redis服务+自定义逻辑实现互斥控制。
准备Redis连接与唯一锁标识
在扣子「Bot设置 → 插件/自定义函数」中启用HTTP请求能力,或使用「代码块」调用外部服务。先确认已部署可公网访问的Redis实例(建议6.2+版本),并获取连接地址、端口、密码及DB编号。
为每次关键操作生成【带业务上下文的唯一锁Key】:格式为lock:{bot_id}:{scene}:{resource_id},例如lock:738291:order_create:u_456789。其中bot_id来自扣子后台URL路径,scene标识场景(如stock_deduct),resource_id是用户ID、商品SKU等实际业务主键——漏掉任一字段都可能导致锁粒度失效。
客户端值(value)必须是全局唯一随机串,推荐用UUIDv4 + 时间戳拼接,如u4d8a2f1-9b3c-4e7e-a0f1-5c8d9e7f2a1b_1722214389。不能用固定字符串或纯时间戳,否则无法防误删。
原子加锁:一步完成判断、设值、过期
使用Redis SET 命令的原子组合参数,禁止分两步执行SETNX + EXPIRE。
方法一:直接调用Redis CLI或兼容协议的HTTP API(如RedisJSON REST Proxy)
SET lock:738291:stock_deduct:sku_1001 u4d8a2f1-9b3c-4e7e-a0f1-5c8d9e7f2a1b_1722214389 NX PX 15000
方法二:若通过扣子「代码块」调用自建中转服务(推荐),在Node.js/Python服务中封装该命令。Python示例:
Redis 8.2.3 是一款安全优先的高性能键值存储系统。该版本紧急修复了可能引发远程代码执行(RCE)的高危漏洞(CVE-2025-62507),并解决了 HyperLogLog 及 Cuckoo Filter 等数据结构在特定场景下的崩溃问题。建议所有用户立即升级,以保障生产环境的系统稳定与数据安全。
redis_client.set("lock:738291:stock_deduct:sku_1001", "u4d8a2f1-9b3c-4e7e-a0f1-5c8d9e7f2a1b_1722214389", nx=True, px=15000)
注意:【PX单位是毫秒,不是秒;15秒是安全下限,低于10秒易被业务超时误释放】。返回OK表示抢锁成功,返回None或nil表示锁已被占用,此时应立即返回错误提示给用户,不要重试。
安全释放锁:Lua脚本校验后删除
释放锁必须用Lua脚本保证“读-判-删”三步原子性,否则可能删掉别人刚持有的锁。
第一步:将以下Lua脚本部署到你的Redis服务可执行位置(或由中转服务调用)
if redis.call("GET", KEYS[1]) == ARGV[1] then return redis.call("DEL", KEYS[1]) else return 0 end
第二步:在扣子工作流的「最终清理」环节(无论业务成功或失败),传入相同key和value发起调用
第三步:检查返回值——返回1表示删除成功,返回0说明锁已不属于当前客户端,无需处理
这一步不可省略。若只依赖过期自动释放,一旦业务耗时超过设定时间,后续操作就失去互斥保障。










