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

CircleCI并行执行引发时间相关测试异常的问题排查

CircleCI并行测试时间相关异常的原因与解决办法

一、记录时间戳重复问题

原因

CircleCI并行执行时,多个测试进程会同时向数据库写入数据。如果created_at由数据库自动生成,高并发写入场景下,部分数据库默认的秒级时钟精度可能导致多条记录时间戳完全一致;如果是应用层生成时间戳,并行进程的操作速度过快或时钟同步问题也会引发重复。而本地串行测试时,记录创建有自然时间间隔,不会触发该问题。

解决办法

  • 改用自增ID排序:把order(created_at: :desc).first替换为order(id: :desc).first,自增ID严格递增,完全不会出现重复,这是最可靠的方案。
  • 提升时间戳精度:确保数据库和应用层使用毫秒/纳秒级时间戳(比如PostgreSQL的timestamp with time zone,Ruby的Time.now默认支持纳秒),大幅降低重复概率。
  • 测试中手动控制时间:在创建多条测试记录时,手动指定不同的created_at值,比如create(:record, created_at: 1.second.ago)、create(:record, created_at: Time.now)。

二、Sleep测试失效问题

原因

CircleCI的虚拟化环境为了提升测试效率,可能对sleep调用做了优化(跳过真实等待);另外如果你的BenchmarkLog是基于CPU时间而非墙上时间计算耗时,sleep期间CPU不工作,统计结果就会显示为0.0。本地和非并行场景下没有这类优化,所以测试正常。

解决办法

  • 用时间模拟替代真实sleep:使用timecop gem模拟时间流逝,既不拖慢测试速度,又能准确验证时长统计。示例代码:
    Timecop.freeze do
      BenchmarkLog.record("test_sleep") do
        Timecop.travel(1.second)
      end
      # 断言统计的耗时为1秒
    end
    
  • 修正BenchmarkLog的时间计算逻辑:确保它使用墙上时间(Time.now的差值)而非CPU时间。比如:
    class BenchmarkLog
      def self.record(name)
        start = Time.now
        yield
        duration = Time.now - start
        puts "#{name} took #{duration} seconds"
      end
    end
    
  • 避免依赖真实sleep的测试:这类测试本身受环境影响大,稳定性差,改用模拟时间是更优的实践。

内容的提问来源于stack exchange,提问作者João Menighin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 20:35:11