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

Rails项目GitLab CI/CD缓存Ruby gem时ox库C扩展加载失败求助

问题描述

我为Rails应用搭建了包含三个阶段的GitLab CI/CD流程,第一阶段负责缓存gem与资源,配置如下:

cache: &default-cache
  untracked: true
  key: "assets-compile:vendor_ruby:.yarn-cache:tmp_cache_assets_sprockets:v3"
  paths:
    - vendor/ruby/
    - .yarn-cache/
    - public/assets/
    - node_modules/
  policy: pull-push

后续测试阶段从vendor/ruby目录拉取缓存的gem,配置如下:

testing:
  cache:
    <<: *default-cache
    policy: pull
  stage: test
  image: "ruby:3.0"
  timeout: one hour
  script:
  - apt-get update -qq && apt-get install -y -qq nodejs
  - export PATH="/usr/local/bundle/bin:$PATH"
  - bundle config set --local path 'vendor/ruby'
  - RAILS_ENV=test bundle install -j $(nproc)

流程整体运行正常,但gem ox抛出LoadError:

Failure/Error: require 'ox'

LoadError:
  cannot load such file -- ox/ox
# ./vendor/ruby/ruby/3.0.0/gems/zeitwerk-2.6.6/lib/zeitwerk/kernel.rb:38:in `require'
# ./vendor/ruby/ruby/3.0.0/gems/zeitwerk-2.6.6/lib/zeitwerk/kernel.rb:38:in `require'
# ./vendor/ruby/ruby/3.0.0/gems/ox-2.14.11/lib/ox.rb:79:in `<top (required)>'

推测问题在于缓存阶段未编译C扩展,导致无法加载生成的ox/ox文件。已尝试移除Gemfile中的require: false,但未解决问题,请问该如何处理?

解决方案

你的推测完全正确,ox是带有C扩展的gem,缓存的vendor/ruby仅包含gem源码,缺少编译后的二进制文件,因此测试阶段拉取缓存后无法加载。以下是几种可行的解决方法:

1. 缓存编译后的扩展文件

修改缓存配置,加入Ruby扩展的编译产物目录。Ruby 3.0的扩展文件通常存放在vendor/ruby/ruby/3.0.0/extensions/路径下,更新缓存的paths字段:

cache: &default-cache
  untracked: true
  key: "assets-compile:vendor_ruby:.yarn-cache:tmp_cache_assets_sprockets:v3"
  paths:
    - vendor/ruby/
    - .yarn-cache/
    - public/assets/
    - node_modules/
    - vendor/ruby/ruby/3.0.0/extensions/  # 新增编译产物路径
  policy: pull-push

注意:后续更换Ruby版本时,需同步更新缓存key和路径中的版本号,避免缓存不兼容。

2. 在测试阶段强制重新编译C扩展

在测试阶段的脚本中,添加重新编译ox扩展的命令,或者使用bundle install --force强制重新安装带C扩展的gem:
修改测试阶段的script部分:

script:
- apt-get update -qq && apt-get install -y -qq nodejs
- export PATH="/usr/local/bundle/bin:$PATH"
- bundle config set --local path 'vendor/ruby'
- RAILS_ENV=test bundle install -j $(nproc)
- bundle exec gem pristine ox  # 重新编译ox的C扩展

若使用bundle install --force替换原bundle install,会重新安装所有gem,可能增加执行耗时,按需选择。

3. 拆分缓存策略,分离纯Ruby与带C扩展的gem

如果担心不同环境的二进制扩展不兼容,可将带C扩展的ox排除在缓存外,测试阶段单独安装:

  • 先修改缓存配置,排除vendor/ruby/ruby/3.0.0/gems/ox-*目录
  • 测试阶段脚本调整为:
script:
- apt-get update -qq && apt-get install -y -qq nodejs
- export PATH="/usr/local/bundle/bin:$PATH"
- bundle config set --local path 'vendor/ruby'
- RAILS_ENV=test bundle install -j $(nproc) --without none  # 安装其他gem
- RAILS_ENV=test bundle install --force ox  # 强制重新安装并编译ox

4. 确保缓存阶段完成C扩展编译

如果缓存阶段由专门的job生成,需确保该job执行完整的bundle install,触发C扩展编译。比如添加一个缓存构建job:

cache-job:
  cache: *default-cache
  stage: build
  image: "ruby:3.0"
  script:
  - apt-get update -qq && apt-get install -y -qq nodejs
  - bundle config set --local path 'vendor/ruby'
  - RAILS_ENV=test bundle install -j $(nproc)

这样缓存的vendor/ruby就包含了编译好的扩展文件,测试阶段拉取后可直接使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 11:05:23